"""
API Routes fuer Alert Digests (Wochenzusammenfassungen).

Endpoints:
- GET /digests - Liste aller Digests fuer den User
- GET /digests/{id} - Digest-Details
- GET /digests/{id}/pdf - PDF-Download
- POST /digests/generate - Digest manuell generieren
- POST /digests/{id}/send-email - Digest per E-Mail versenden
"""

import uuid
import io
from typing import Optional, List
from datetime import datetime, timedelta
from fastapi import APIRouter, Depends, HTTPException, Query, Response
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
from sqlalchemy.orm import Session as DBSession

from ..db.database import get_db
from ..db.models import (
    AlertDigestDB, UserAlertSubscriptionDB, DigestStatusEnum
)
from ..processing.digest_generator import DigestGenerator


router = APIRouter(prefix="/digests", tags=["digests"])


# ============================================================================
# Request/Response Models
# ============================================================================

class DigestListItem(BaseModel):
    """Kurze Digest-Info fuer Liste."""
    id: str
    period_start: datetime
    period_end: datetime
    total_alerts: int
    critical_count: int
    urgent_count: int
    status: str
    created_at: datetime


class DigestDetail(BaseModel):
    """Vollstaendige Digest-Details."""
    id: str
    subscription_id: Optional[str]
    user_id: str
    period_start: datetime
    period_end: datetime
    summary_html: str
    summary_pdf_url: Optional[str]
    total_alerts: int
    critical_count: int
    urgent_count: int
    important_count: int
    review_count: int
    info_count: int
    status: str
    sent_at: Optional[datetime]
    created_at: datetime


class DigestListResponse(BaseModel):
    """Response fuer Digest-Liste."""
    digests: List[DigestListItem]
    total: int


class GenerateDigestRequest(BaseModel):
    """Request fuer manuelle Digest-Generierung."""
    weeks_back: int = Field(default=1, ge=1, le=4, description="Wochen zurueck")
    force_regenerate: bool = Field(default=False, description="Vorhandenen Digest ueberschreiben")


class GenerateDigestResponse(BaseModel):
    """Response fuer Digest-Generierung."""
    status: str
    digest_id: Optional[str]
    message: str


class SendEmailRequest(BaseModel):
    """Request fuer E-Mail-Versand."""
    email: Optional[str] = Field(default=None, description="E-Mail-Adresse (optional, sonst aus Subscription)")


class SendEmailResponse(BaseModel):
    """Response fuer E-Mail-Versand."""
    status: str
    sent_to: str
    message: str


# ============================================================================
# Helper Functions
# ============================================================================

def get_user_id_from_request() -> str:
    """
    Extrahiert User-ID aus Request.
    TODO: JWT-Token auswerten, aktuell Dummy.
    """
    return "demo-user"


def _digest_to_list_item(digest: AlertDigestDB) -> DigestListItem:
    """Konvertiere DB-Model zu List-Item."""
    return DigestListItem(
        id=digest.id,
        period_start=digest.period_start,
        period_end=digest.period_end,
        total_alerts=digest.total_alerts or 0,
        critical_count=digest.critical_count or 0,
        urgent_count=digest.urgent_count or 0,
        status=digest.status.value if digest.status else "pending",
        created_at=digest.created_at
    )


def _digest_to_detail(digest: AlertDigestDB) -> DigestDetail:
    """Konvertiere DB-Model zu Detail."""
    return DigestDetail(
        id=digest.id,
        subscription_id=digest.subscription_id,
        user_id=digest.user_id,
        period_start=digest.period_start,
        period_end=digest.period_end,
        summary_html=digest.summary_html or "",
        summary_pdf_url=digest.summary_pdf_url,
        total_alerts=digest.total_alerts or 0,
        critical_count=digest.critical_count or 0,
        urgent_count=digest.urgent_count or 0,
        important_count=digest.important_count or 0,
        review_count=digest.review_count or 0,
        info_count=digest.info_count or 0,
        status=digest.status.value if digest.status else "pending",
        sent_at=digest.sent_at,
        created_at=digest.created_at
    )


# ============================================================================
# Endpoints
# ============================================================================

@router.get("", response_model=DigestListResponse)
async def list_digests(
    limit: int = Query(10, ge=1, le=50),
    offset: int = Query(0, ge=0),
    db: DBSession = Depends(get_db)
):
    """
    Liste alle Digests des aktuellen Users.

    Sortiert nach Erstellungsdatum (neueste zuerst).
    """
    user_id = get_user_id_from_request()

    query = db.query(AlertDigestDB).filter(
        AlertDigestDB.user_id == user_id
    ).order_by(AlertDigestDB.created_at.desc())

    total = query.count()
    digests = query.offset(offset).limit(limit).all()

    return DigestListResponse(
        digests=[_digest_to_list_item(d) for d in digests],
        total=total
    )


@router.get("/latest", response_model=DigestDetail)
async def get_latest_digest(
    db: DBSession = Depends(get_db)
):
    """
    Hole den neuesten Digest des Users.
    """
    user_id = get_user_id_from_request()

    digest = db.query(AlertDigestDB).filter(
        AlertDigestDB.user_id == user_id
    ).order_by(AlertDigestDB.created_at.desc()).first()

    if not digest:
        raise HTTPException(status_code=404, detail="Kein Digest vorhanden")

    return _digest_to_detail(digest)


@router.get("/{digest_id}", response_model=DigestDetail)
async def get_digest(
    digest_id: str,
    db: DBSession = Depends(get_db)
):
    """
    Hole Details eines spezifischen Digests.
    """
    user_id = get_user_id_from_request()

    digest = db.query(AlertDigestDB).filter(
        AlertDigestDB.id == digest_id,
        AlertDigestDB.user_id == user_id
    ).first()

    if not digest:
        raise HTTPException(status_code=404, detail="Digest nicht gefunden")

    return _digest_to_detail(digest)


@router.get("/{digest_id}/pdf")
async def get_digest_pdf(
    digest_id: str,
    db: DBSession = Depends(get_db)
):
    """
    Generiere und lade PDF-Version des Digests herunter.
    """
    user_id = get_user_id_from_request()

    digest = db.query(AlertDigestDB).filter(
        AlertDigestDB.id == digest_id,
        AlertDigestDB.user_id == user_id
    ).first()

    if not digest:
        raise HTTPException(status_code=404, detail="Digest nicht gefunden")

    if not digest.summary_html:
        raise HTTPException(status_code=400, detail="Digest hat keinen Inhalt")

    # PDF generieren
    try:
        pdf_bytes = await generate_pdf_from_html(digest.summary_html)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"PDF-Generierung fehlgeschlagen: {str(e)}")

    # Dateiname
    filename = f"wochenbericht_{digest.period_start.strftime('%Y%m%d')}_{digest.period_end.strftime('%Y%m%d')}.pdf"

    return StreamingResponse(
        io.BytesIO(pdf_bytes),
        media_type="application/pdf",
        headers={
            "Content-Disposition": f"attachment; filename={filename}"
        }
    )


@router.get("/latest/pdf")
async def get_latest_digest_pdf(
    db: DBSession = Depends(get_db)
):
    """
    PDF des neuesten Digests herunterladen.
    """
    user_id = get_user_id_from_request()

    digest = db.query(AlertDigestDB).filter(
        AlertDigestDB.user_id == user_id
    ).order_by(AlertDigestDB.created_at.desc()).first()

    if not digest:
        raise HTTPException(status_code=404, detail="Kein Digest vorhanden")

    if not digest.summary_html:
        raise HTTPException(status_code=400, detail="Digest hat keinen Inhalt")

    # PDF generieren
    try:
        pdf_bytes = await generate_pdf_from_html(digest.summary_html)
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"PDF-Generierung fehlgeschlagen: {str(e)}")

    filename = f"wochenbericht_{digest.period_start.strftime('%Y%m%d')}_{digest.period_end.strftime('%Y%m%d')}.pdf"

    return StreamingResponse(
        io.BytesIO(pdf_bytes),
        media_type="application/pdf",
        headers={
            "Content-Disposition": f"attachment; filename={filename}"
        }
    )


@router.post("/generate", response_model=GenerateDigestResponse)
async def generate_digest(
    request: GenerateDigestRequest = None,
    db: DBSession = Depends(get_db)
):
    """
    Generiere einen neuen Digest manuell.

    Normalerweise werden Digests automatisch woechentlich generiert.
    Diese Route erlaubt manuelle Generierung fuer Tests oder On-Demand.
    """
    user_id = get_user_id_from_request()
    weeks_back = request.weeks_back if request else 1

    # Pruefe ob bereits ein Digest fuer diesen Zeitraum existiert
    now = datetime.utcnow()
    period_end = now - timedelta(days=now.weekday())
    period_start = period_end - timedelta(weeks=weeks_back)

    existing = db.query(AlertDigestDB).filter(
        AlertDigestDB.user_id == user_id,
        AlertDigestDB.period_start >= period_start - timedelta(days=1),
        AlertDigestDB.period_end <= period_end + timedelta(days=1)
    ).first()

    if existing and not (request and request.force_regenerate):
        return GenerateDigestResponse(
            status="exists",
            digest_id=existing.id,
            message="Digest fuer diesen Zeitraum existiert bereits"
        )

    # Generiere neuen Digest
    generator = DigestGenerator(db)

    try:
        digest = await generator.generate_weekly_digest(user_id, weeks_back)

        if digest:
            return GenerateDigestResponse(
                status="success",
                digest_id=digest.id,
                message="Digest erfolgreich generiert"
            )
        else:
            return GenerateDigestResponse(
                status="empty",
                digest_id=None,
                message="Keine Alerts fuer diesen Zeitraum vorhanden"
            )
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Fehler bei Digest-Generierung: {str(e)}")


@router.post("/{digest_id}/send-email", response_model=SendEmailResponse)
async def send_digest_email(
    digest_id: str,
    request: SendEmailRequest = None,
    db: DBSession = Depends(get_db)
):
    """
    Versende Digest per E-Mail.
    """
    user_id = get_user_id_from_request()

    digest = db.query(AlertDigestDB).filter(
        AlertDigestDB.id == digest_id,
        AlertDigestDB.user_id == user_id
    ).first()

    if not digest:
        raise HTTPException(status_code=404, detail="Digest nicht gefunden")

    # E-Mail-Adresse ermitteln
    email = None
    if request and request.email:
        email = request.email
    else:
        # Aus Subscription holen
        subscription = db.query(UserAlertSubscriptionDB).filter(
            UserAlertSubscriptionDB.id == digest.subscription_id
        ).first()
        if subscription:
            email = subscription.notification_email

    if not email:
        raise HTTPException(status_code=400, detail="Keine E-Mail-Adresse angegeben")

    # E-Mail versenden
    try:
        await send_digest_by_email(digest, email)

        # Status aktualisieren
        digest.status = DigestStatusEnum.SENT
        digest.sent_at = datetime.utcnow()
        db.commit()

        return SendEmailResponse(
            status="success",
            sent_to=email,
            message="E-Mail erfolgreich versendet"
        )
    except Exception as e:
        digest.status = DigestStatusEnum.FAILED
        db.commit()
        raise HTTPException(status_code=500, detail=f"E-Mail-Versand fehlgeschlagen: {str(e)}")


# ============================================================================
# PDF Generation
# ============================================================================

async def generate_pdf_from_html(html_content: str) -> bytes:
    """
    Generiere PDF aus HTML.

    Verwendet WeasyPrint oder wkhtmltopdf als Fallback.
    """
    try:
        # Versuche WeasyPrint (bevorzugt)
        from weasyprint import HTML
        pdf_bytes = HTML(string=html_content).write_pdf()
        return pdf_bytes
    except ImportError:
        pass

    try:
        # Fallback: wkhtmltopdf via pdfkit
        import pdfkit
        pdf_bytes = pdfkit.from_string(html_content, False)
        return pdf_bytes
    except ImportError:
        pass

    try:
        # Fallback: xhtml2pdf
        from xhtml2pdf import pisa
        result = io.BytesIO()
        pisa.CreatePDF(io.StringIO(html_content), dest=result)
        return result.getvalue()
    except ImportError:
        pass

    # Letzter Fallback: Einfache Text-Konvertierung
    raise ImportError(
        "Keine PDF-Bibliothek verfuegbar. "
        "Installieren Sie: pip install weasyprint oder pip install pdfkit oder pip install xhtml2pdf"
    )


# ============================================================================
# Email Sending
# ============================================================================

async def send_digest_by_email(digest: AlertDigestDB, recipient_email: str):
    """
    Versende Digest per E-Mail.

    Verwendet:
    - Lokalen SMTP-Server (Postfix/Sendmail)
    - SMTP-Relay (z.B. SES, Mailgun)
    - SendGrid API
    """
    import os
    import smtplib
    from email.mime.text import MIMEText
    from email.mime.multipart import MIMEMultipart
    from email.mime.application import MIMEApplication

    # E-Mail zusammenstellen
    msg = MIMEMultipart('alternative')
    msg['Subject'] = f"Wochenbericht: {digest.period_start.strftime('%d.%m.%Y')} - {digest.period_end.strftime('%d.%m.%Y')}"
    msg['From'] = os.getenv('SMTP_FROM', 'alerts@breakpilot.app')
    msg['To'] = recipient_email

    # Text-Version
    text_content = f"""
BreakPilot Alerts - Wochenbericht

Zeitraum: {digest.period_start.strftime('%d.%m.%Y')} - {digest.period_end.strftime('%d.%m.%Y')}
Gesamt: {digest.total_alerts} Meldungen
Kritisch: {digest.critical_count}
Dringend: {digest.urgent_count}

Oeffnen Sie die HTML-Version fuer die vollstaendige Uebersicht.

---
Diese E-Mail wurde automatisch von BreakPilot Alerts generiert.
    """
    msg.attach(MIMEText(text_content, 'plain', 'utf-8'))

    # HTML-Version
    if digest.summary_html:
        msg.attach(MIMEText(digest.summary_html, 'html', 'utf-8'))

    # PDF-Anhang (optional)
    try:
        pdf_bytes = await generate_pdf_from_html(digest.summary_html)
        pdf_attachment = MIMEApplication(pdf_bytes, _subtype='pdf')
        pdf_attachment.add_header(
            'Content-Disposition', 'attachment',
            filename=f"wochenbericht_{digest.period_start.strftime('%Y%m%d')}.pdf"
        )
        msg.attach(pdf_attachment)
    except Exception:
        pass  # PDF-Anhang ist optional

    # Senden
    smtp_host = os.getenv('SMTP_HOST', 'localhost')
    smtp_port = int(os.getenv('SMTP_PORT', '25'))
    smtp_user = os.getenv('SMTP_USER', '')
    smtp_pass = os.getenv('SMTP_PASS', '')

    try:
        if smtp_port == 465:
            # SSL
            server = smtplib.SMTP_SSL(smtp_host, smtp_port)
        else:
            server = smtplib.SMTP(smtp_host, smtp_port)
            if smtp_port == 587:
                server.starttls()

        if smtp_user and smtp_pass:
            server.login(smtp_user, smtp_pass)

        server.send_message(msg)
        server.quit()

    except Exception as e:
        # Fallback: SendGrid API
        sendgrid_key = os.getenv('SENDGRID_API_KEY')
        if sendgrid_key:
            await send_via_sendgrid(msg, sendgrid_key)
        else:
            raise e


async def send_via_sendgrid(msg, api_key: str):
    """Fallback: SendGrid API."""
    import httpx

    async with httpx.AsyncClient() as client:
        response = await client.post(
            "https://api.sendgrid.com/v3/mail/send",
            headers={
                "Authorization": f"Bearer {api_key}",
                "Content-Type": "application/json"
            },
            json={
                "personalizations": [{"to": [{"email": msg['To']}]}],
                "from": {"email": msg['From']},
                "subject": msg['Subject'],
                "content": [
                    {"type": "text/plain", "value": msg.get_payload(0).get_payload()},
                    {"type": "text/html", "value": msg.get_payload(1).get_payload() if len(msg.get_payload()) > 1 else ""}
                ]
            }
        )

        if response.status_code >= 400:
            raise Exception(f"SendGrid error: {response.status_code}")
