"""
Letters API - Elternbrief-Verwaltung für BreakPilot.

Bietet Endpoints für:
- Speichern und Laden von Elternbriefen
- PDF-Export von Briefen
- Versenden per Email
- GFK-Integration für Textverbesserung

Arbeitet zusammen mit:
- services/pdf_service.py für PDF-Generierung
- llm_gateway/services/communication_service.py für GFK-Verbesserungen
"""

import logging
import os
import uuid
from datetime import datetime
from typing import Optional, List, Dict, Any
from enum import Enum

from fastapi import APIRouter, HTTPException, Response, Query
from fastapi.responses import StreamingResponse
from pydantic import BaseModel, Field
import httpx
import io

# PDF service requires WeasyPrint with system libraries - make optional for CI
try:
    from services.pdf_service import generate_letter_pdf, SchoolInfo
    _pdf_available = True
except (ImportError, OSError):
    generate_letter_pdf = None  # type: ignore
    SchoolInfo = None  # type: ignore
    _pdf_available = False

logger = logging.getLogger(__name__)

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


# =============================================================================
# Enums
# =============================================================================

class LetterType(str, Enum):
    """Typen von Elternbriefen."""
    GENERAL = "general"              # Allgemeine Information
    HALBJAHR = "halbjahr"           # Halbjahresinformation
    FEHLZEITEN = "fehlzeiten"       # Fehlzeiten-Mitteilung
    ELTERNABEND = "elternabend"     # Einladung Elternabend
    LOB = "lob"                      # Positives Feedback
    CUSTOM = "custom"                # Benutzerdefiniert


class LetterTone(str, Enum):
    """Tonalität der Briefe."""
    FORMAL = "formal"
    PROFESSIONAL = "professional"
    WARM = "warm"
    CONCERNED = "concerned"
    APPRECIATIVE = "appreciative"


class LetterStatus(str, Enum):
    """Status eines Briefes."""
    DRAFT = "draft"
    SENT = "sent"
    ARCHIVED = "archived"


# =============================================================================
# Pydantic Models
# =============================================================================

class SchoolInfoModel(BaseModel):
    """Schulinformationen für Briefkopf."""
    name: str
    address: str
    phone: str
    email: str
    website: Optional[str] = None
    principal: Optional[str] = None
    logo_path: Optional[str] = None


class LegalReferenceModel(BaseModel):
    """Rechtliche Referenz."""
    law: str
    paragraph: str
    title: str
    summary: Optional[str] = None
    relevance: Optional[str] = None


class LetterCreateRequest(BaseModel):
    """Request zum Erstellen eines neuen Briefes."""
    recipient_name: str = Field(..., description="Name des Empfängers (z.B. 'Familie Müller')")
    recipient_address: str = Field(..., description="Adresse des Empfängers")
    student_name: str = Field(..., description="Name des Schülers")
    student_class: str = Field(..., description="Klasse des Schülers")
    subject: str = Field(..., description="Betreff des Briefes")
    content: str = Field(..., description="Inhalt des Briefes")
    letter_type: LetterType = Field(LetterType.GENERAL, description="Art des Briefes")
    tone: LetterTone = Field(LetterTone.PROFESSIONAL, description="Tonalität des Briefes")
    teacher_name: str = Field(..., description="Name des Lehrers")
    teacher_title: Optional[str] = Field(None, description="Titel des Lehrers (z.B. 'Klassenlehrerin')")
    school_info: Optional[SchoolInfoModel] = Field(None, description="Schulinformationen für Briefkopf")
    legal_references: Optional[List[LegalReferenceModel]] = Field(None, description="Rechtliche Referenzen")
    gfk_principles_applied: Optional[List[str]] = Field(None, description="Angewandte GFK-Prinzipien")


class LetterUpdateRequest(BaseModel):
    """Request zum Aktualisieren eines Briefes."""
    recipient_name: Optional[str] = None
    recipient_address: Optional[str] = None
    student_name: Optional[str] = None
    student_class: Optional[str] = None
    subject: Optional[str] = None
    content: Optional[str] = None
    letter_type: Optional[LetterType] = None
    tone: Optional[LetterTone] = None
    teacher_name: Optional[str] = None
    teacher_title: Optional[str] = None
    school_info: Optional[SchoolInfoModel] = None
    legal_references: Optional[List[LegalReferenceModel]] = None
    gfk_principles_applied: Optional[List[str]] = None
    status: Optional[LetterStatus] = None


class LetterResponse(BaseModel):
    """Response mit Briefdaten."""
    id: str
    recipient_name: str
    recipient_address: str
    student_name: str
    student_class: str
    subject: str
    content: str
    letter_type: LetterType
    tone: LetterTone
    teacher_name: str
    teacher_title: Optional[str]
    school_info: Optional[SchoolInfoModel]
    legal_references: Optional[List[LegalReferenceModel]]
    gfk_principles_applied: Optional[List[str]]
    gfk_score: Optional[float]
    status: LetterStatus
    pdf_path: Optional[str]
    dsms_cid: Optional[str]
    sent_at: Optional[datetime]
    created_at: datetime
    updated_at: datetime


class LetterListResponse(BaseModel):
    """Response mit Liste von Briefen."""
    letters: List[LetterResponse]
    total: int
    page: int
    page_size: int


class ExportPDFRequest(BaseModel):
    """Request zum PDF-Export."""
    letter_id: Optional[str] = Field(None, description="ID eines gespeicherten Briefes")
    letter_data: Optional[LetterCreateRequest] = Field(None, description="Oder direkte Briefdaten")


class ImproveRequest(BaseModel):
    """Request zur GFK-Verbesserung."""
    content: str = Field(..., description="Text zur Verbesserung")
    communication_type: Optional[str] = Field("general_info", description="Art der Kommunikation")
    tone: Optional[str] = Field("professional", description="Gewünschte Tonalität")


class ImproveResponse(BaseModel):
    """Response mit verbessertem Text."""
    improved_content: str
    changes: List[str]
    gfk_score: float
    gfk_principles_applied: List[str]


class SendEmailRequest(BaseModel):
    """Request zum Email-Versand."""
    letter_id: str
    recipient_email: str
    cc_emails: Optional[List[str]] = None
    include_pdf: bool = True


class SendEmailResponse(BaseModel):
    """Response nach Email-Versand."""
    success: bool
    message: str
    sent_at: Optional[datetime]


# =============================================================================
# In-Memory Storage (Prototyp - später durch DB ersetzen)
# =============================================================================

_letters_store: Dict[str, Dict[str, Any]] = {}


def _get_letter(letter_id: str) -> Dict[str, Any]:
    """Holt Brief aus dem Store."""
    if letter_id not in _letters_store:
        raise HTTPException(status_code=404, detail=f"Brief mit ID {letter_id} nicht gefunden")
    return _letters_store[letter_id]


def _save_letter(letter_data: Dict[str, Any]) -> str:
    """Speichert Brief und gibt ID zurück."""
    letter_id = letter_data.get("id") or str(uuid.uuid4())
    letter_data["id"] = letter_id
    letter_data["updated_at"] = datetime.now()
    if "created_at" not in letter_data:
        letter_data["created_at"] = datetime.now()
    _letters_store[letter_id] = letter_data
    return letter_id


# =============================================================================
# API Endpoints
# =============================================================================

@router.post("/", response_model=LetterResponse)
async def create_letter(request: LetterCreateRequest):
    """
    Erstellt einen neuen Elternbrief.

    Der Brief wird als Entwurf gespeichert und kann später bearbeitet,
    als PDF exportiert oder per Email versendet werden.
    """
    logger.info(f"Creating new letter for student: {request.student_name}")

    letter_data = {
        "recipient_name": request.recipient_name,
        "recipient_address": request.recipient_address,
        "student_name": request.student_name,
        "student_class": request.student_class,
        "subject": request.subject,
        "content": request.content,
        "letter_type": request.letter_type,
        "tone": request.tone,
        "teacher_name": request.teacher_name,
        "teacher_title": request.teacher_title,
        "school_info": request.school_info.model_dump() if request.school_info else None,
        "legal_references": [ref.model_dump() for ref in request.legal_references] if request.legal_references else None,
        "gfk_principles_applied": request.gfk_principles_applied,
        "gfk_score": None,
        "status": LetterStatus.DRAFT,
        "pdf_path": None,
        "dsms_cid": None,
        "sent_at": None,
    }

    letter_id = _save_letter(letter_data)
    letter_data["id"] = letter_id

    logger.info(f"Letter created with ID: {letter_id}")
    return LetterResponse(**letter_data)


# NOTE: Static routes must come BEFORE dynamic routes like /{letter_id}
@router.get("/types")
async def get_letter_types():
    """
    Gibt alle verfügbaren Brieftypen zurück.
    """
    return {
        "types": [
            {"value": t.value, "label": _get_type_label(t)}
            for t in LetterType
        ]
    }


@router.get("/tones")
async def get_letter_tones():
    """
    Gibt alle verfügbaren Tonalitäten zurück.
    """
    return {
        "tones": [
            {"value": t.value, "label": _get_tone_label(t)}
            for t in LetterTone
        ]
    }


@router.get("/{letter_id}", response_model=LetterResponse)
async def get_letter(letter_id: str):
    """
    Lädt einen gespeicherten Brief.
    """
    logger.info(f"Getting letter: {letter_id}")
    letter_data = _get_letter(letter_id)
    return LetterResponse(**letter_data)


@router.get("/", response_model=LetterListResponse)
async def list_letters(
    student_id: Optional[str] = Query(None, description="Filter nach Schüler-ID"),
    class_name: Optional[str] = Query(None, description="Filter nach Klasse"),
    letter_type: Optional[LetterType] = Query(None, description="Filter nach Brief-Typ"),
    status: Optional[LetterStatus] = Query(None, description="Filter nach Status"),
    page: int = Query(1, ge=1, description="Seitennummer"),
    page_size: int = Query(20, ge=1, le=100, description="Einträge pro Seite")
):
    """
    Listet alle gespeicherten Briefe mit optionalen Filtern.
    """
    logger.info("Listing letters with filters")

    # Filter anwenden
    filtered_letters = list(_letters_store.values())

    if class_name:
        filtered_letters = [l for l in filtered_letters if l.get("student_class") == class_name]
    if letter_type:
        filtered_letters = [l for l in filtered_letters if l.get("letter_type") == letter_type]
    if status:
        filtered_letters = [l for l in filtered_letters if l.get("status") == status]

    # Sortieren nach Erstelldatum (neueste zuerst)
    filtered_letters.sort(key=lambda x: x.get("created_at", datetime.min), reverse=True)

    # Paginierung
    total = len(filtered_letters)
    start = (page - 1) * page_size
    end = start + page_size
    paginated_letters = filtered_letters[start:end]

    return LetterListResponse(
        letters=[LetterResponse(**l) for l in paginated_letters],
        total=total,
        page=page,
        page_size=page_size
    )


@router.put("/{letter_id}", response_model=LetterResponse)
async def update_letter(letter_id: str, request: LetterUpdateRequest):
    """
    Aktualisiert einen bestehenden Brief.
    """
    logger.info(f"Updating letter: {letter_id}")
    letter_data = _get_letter(letter_id)

    # Nur übergebene Felder aktualisieren
    update_data = request.model_dump(exclude_unset=True)
    for key, value in update_data.items():
        if value is not None:
            if key == "school_info" and value:
                letter_data[key] = value if isinstance(value, dict) else value.model_dump()
            elif key == "legal_references" and value:
                letter_data[key] = [ref if isinstance(ref, dict) else ref.model_dump() for ref in value]
            else:
                letter_data[key] = value

    _save_letter(letter_data)

    return LetterResponse(**letter_data)


@router.delete("/{letter_id}")
async def delete_letter(letter_id: str):
    """
    Löscht einen Brief.
    """
    logger.info(f"Deleting letter: {letter_id}")
    if letter_id not in _letters_store:
        raise HTTPException(status_code=404, detail=f"Brief mit ID {letter_id} nicht gefunden")

    del _letters_store[letter_id]
    return {"message": f"Brief {letter_id} wurde gelöscht"}


@router.post("/export-pdf")
async def export_letter_pdf(request: ExportPDFRequest):
    """
    Exportiert einen Brief als PDF.

    Kann entweder einen gespeicherten Brief (per letter_id) oder
    direkte Briefdaten (per letter_data) als PDF exportieren.

    Gibt das PDF als Download zurück.
    """
    logger.info("Exporting letter as PDF")

    # Briefdaten ermitteln
    if request.letter_id:
        letter_data = _get_letter(request.letter_id)
    elif request.letter_data:
        letter_data = request.letter_data.model_dump()
    else:
        raise HTTPException(
            status_code=400,
            detail="Entweder letter_id oder letter_data muss angegeben werden"
        )

    # Datum hinzufügen falls nicht vorhanden
    if "date" not in letter_data:
        letter_data["date"] = datetime.now().strftime("%d.%m.%Y")

    # PDF generieren
    try:
        pdf_bytes = generate_letter_pdf(letter_data)
    except Exception as e:
        logger.error(f"Error generating PDF: {e}")
        raise HTTPException(status_code=500, detail=f"Fehler bei PDF-Generierung: {str(e)}")

    # Dateiname erstellen
    student_name = letter_data.get("student_name", "Brief").replace(" ", "_")
    date_str = datetime.now().strftime("%Y%m%d")
    filename = f"Elternbrief_{student_name}_{date_str}.pdf"

    # PDF als Download zurückgeben
    return Response(
        content=pdf_bytes,
        media_type="application/pdf",
        headers={
            "Content-Disposition": f"attachment; filename={filename}",
            "Content-Length": str(len(pdf_bytes))
        }
    )


@router.post("/{letter_id}/export-pdf")
async def export_saved_letter_pdf(letter_id: str):
    """
    Exportiert einen gespeicherten Brief als PDF (Kurzform).
    """
    return await export_letter_pdf(ExportPDFRequest(letter_id=letter_id))


@router.post("/improve", response_model=ImproveResponse)
async def improve_letter_content(request: ImproveRequest):
    """
    Verbessert den Briefinhalt nach GFK-Prinzipien.

    Nutzt die Communication Service API für KI-gestützte Verbesserungen.
    """
    logger.info("Improving letter content with GFK principles")

    # Communication Service URL (läuft im gleichen Backend)
    comm_service_url = os.getenv(
        "COMMUNICATION_SERVICE_URL",
        "http://localhost:8000/v1/communication"
    )

    try:
        async with httpx.AsyncClient() as client:
            # Validierung des aktuellen Textes
            validate_response = await client.post(
                f"{comm_service_url}/validate",
                json={"text": request.content},
                timeout=30.0
            )

            if validate_response.status_code != 200:
                logger.warning(f"Validation service returned {validate_response.status_code}")
                # Fallback: Original-Text zurückgeben
                return ImproveResponse(
                    improved_content=request.content,
                    changes=["Verbesserungsservice nicht verfügbar"],
                    gfk_score=0.5,
                    gfk_principles_applied=[]
                )

            validation_data = validate_response.json()

            # Falls Text schon gut ist, keine Änderungen
            if validation_data.get("is_valid", False) and validation_data.get("gfk_score", 0) > 0.8:
                return ImproveResponse(
                    improved_content=request.content,
                    changes=["Text entspricht bereits GFK-Standards"],
                    gfk_score=validation_data.get("gfk_score", 0.8),
                    gfk_principles_applied=validation_data.get("positive_elements", [])
                )

            # Verbesserungsvorschläge als Änderungen
            changes = validation_data.get("suggestions", [])
            gfk_score = validation_data.get("gfk_score", 0.5)
            gfk_principles = validation_data.get("positive_elements", [])

            # TODO: Hier könnte ein LLM den Text basierend auf den Vorschlägen verbessern
            # Für jetzt geben wir den Original-Text mit den Verbesserungsvorschlägen zurück
            return ImproveResponse(
                improved_content=request.content,
                changes=changes,
                gfk_score=gfk_score,
                gfk_principles_applied=gfk_principles
            )

    except httpx.TimeoutException:
        logger.error("Timeout while calling communication service")
        return ImproveResponse(
            improved_content=request.content,
            changes=["Zeitüberschreitung beim Verbesserungsservice"],
            gfk_score=0.5,
            gfk_principles_applied=[]
        )
    except Exception as e:
        logger.error(f"Error improving content: {e}")
        return ImproveResponse(
            improved_content=request.content,
            changes=[f"Fehler: {str(e)}"],
            gfk_score=0.5,
            gfk_principles_applied=[]
        )


@router.post("/{letter_id}/send", response_model=SendEmailResponse)
async def send_letter_email(letter_id: str, request: SendEmailRequest):
    """
    Versendet einen Brief per Email.

    Der Brief wird als PDF angehängt (wenn include_pdf=True)
    und der Status wird auf 'sent' gesetzt.
    """
    logger.info(f"Sending letter {letter_id} to {request.recipient_email}")

    # Brief laden
    letter_data = _get_letter(letter_id)

    # Email-Service URL (Mailpit oder SMTP)
    email_service_url = os.getenv(
        "EMAIL_SERVICE_URL",
        "http://localhost:8025/api/v1/send"  # Mailpit default
    )

    try:
        # PDF generieren falls gewünscht
        pdf_attachment = None
        if request.include_pdf:
            letter_data["date"] = datetime.now().strftime("%d.%m.%Y")
            pdf_bytes = generate_letter_pdf(letter_data)
            pdf_attachment = {
                "filename": f"Elternbrief_{letter_data.get('student_name', 'Brief').replace(' ', '_')}.pdf",
                "content": pdf_bytes.hex(),  # Hex-encoded für JSON
                "content_type": "application/pdf"
            }

        # Email senden (vereinfachte Implementierung)
        # In der Praxis würde hier ein richtiger Email-Service aufgerufen
        async with httpx.AsyncClient() as client:
            email_data = {
                "to": request.recipient_email,
                "cc": request.cc_emails or [],
                "subject": letter_data.get("subject", "Elternbrief"),
                "body": letter_data.get("content", ""),
                "attachments": [pdf_attachment] if pdf_attachment else []
            }

            # Für Prototyp: Nur loggen, nicht wirklich senden
            logger.info(f"Would send email: {email_data['subject']} to {email_data['to']}")

            # Status aktualisieren
            letter_data["status"] = LetterStatus.SENT
            letter_data["sent_at"] = datetime.now()
            _save_letter(letter_data)

            return SendEmailResponse(
                success=True,
                message=f"Brief wurde an {request.recipient_email} gesendet",
                sent_at=datetime.now()
            )

    except Exception as e:
        logger.error(f"Error sending email: {e}")
        return SendEmailResponse(
            success=False,
            message=f"Fehler beim Versenden: {str(e)}",
            sent_at=None
        )


@router.get("/student/{student_id}", response_model=LetterListResponse)
async def get_letters_for_student(
    student_id: str,
    page: int = Query(1, ge=1),
    page_size: int = Query(20, ge=1, le=100)
):
    """
    Lädt alle Briefe für einen bestimmten Schüler.
    """
    logger.info(f"Getting letters for student: {student_id}")

    # In einem echten System würde hier nach student_id gefiltert
    # Für Prototyp filtern wir nach student_name
    filtered_letters = [
        l for l in _letters_store.values()
        if student_id.lower() in l.get("student_name", "").lower()
    ]

    # Sortieren und Paginierung
    filtered_letters.sort(key=lambda x: x.get("created_at", datetime.min), reverse=True)
    total = len(filtered_letters)
    start = (page - 1) * page_size
    end = start + page_size
    paginated_letters = filtered_letters[start:end]

    return LetterListResponse(
        letters=[LetterResponse(**l) for l in paginated_letters],
        total=total,
        page=page,
        page_size=page_size
    )


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

def _get_type_label(letter_type: LetterType) -> str:
    """Gibt menschenlesbare Labels für Brieftypen zurück."""
    labels = {
        LetterType.GENERAL: "Allgemeine Information",
        LetterType.HALBJAHR: "Halbjahresinformation",
        LetterType.FEHLZEITEN: "Fehlzeiten-Mitteilung",
        LetterType.ELTERNABEND: "Einladung Elternabend",
        LetterType.LOB: "Positives Feedback",
        LetterType.CUSTOM: "Benutzerdefiniert",
    }
    return labels.get(letter_type, letter_type.value)


def _get_tone_label(tone: LetterTone) -> str:
    """Gibt menschenlesbare Labels für Tonalitäten zurück."""
    labels = {
        LetterTone.FORMAL: "Sehr förmlich",
        LetterTone.PROFESSIONAL: "Professionell-freundlich",
        LetterTone.WARM: "Warmherzig",
        LetterTone.CONCERNED: "Besorgt",
        LetterTone.APPRECIATIVE: "Wertschätzend",
    }
    return labels.get(tone, tone.value)
