"""
PDF Service - Zentrale PDF-Generierung fuer BreakPilot.

Shared Service fuer:
- Letters (Elternbriefe)
- Zeugnisse (Schulzeugnisse)
- Correction (Korrektur-Uebersichten)

Verwendet WeasyPrint fuer PDF-Rendering und Jinja2 fuer Templates.

Datenmodelle: services/pdf_models.py
HTML-Templates: services/pdf_templates.py
"""

import logging
from datetime import datetime
from pathlib import Path
from typing import Any, Dict, Optional

from jinja2 import Environment, FileSystemLoader, select_autoescape
from weasyprint import HTML, CSS
from weasyprint.text.fonts import FontConfiguration

from .pdf_models import (
    SchoolInfo,
    LetterData,
    CertificateData,
    StudentInfo,
    CorrectionData,
)
from .pdf_templates import (
    get_base_css,
    get_letter_template_html,
    get_certificate_template_html,
    get_correction_template_html,
)

logger = logging.getLogger(__name__)

# Template directory
TEMPLATES_DIR = Path(__file__).parent.parent / "templates" / "pdf"


class PDFService:
    """
    Zentrale PDF-Generierung fuer BreakPilot.

    Unterstuetzt:
    - Elternbriefe mit GFK-Prinzipien und rechtlichen Referenzen
    - Schulzeugnisse (Halbjahr, Jahres, Abschluss)
    - Korrektur-Uebersichten fuer Klausuren
    """

    def __init__(self, templates_dir: Optional[Path] = None):
        """
        Initialisiert den PDF-Service.

        Args:
            templates_dir: Optionaler Pfad zu Templates (Standard: backend/templates/pdf)
        """
        self.templates_dir = templates_dir or TEMPLATES_DIR

        # Ensure templates directory exists
        self.templates_dir.mkdir(parents=True, exist_ok=True)

        # Initialize Jinja2 environment
        self.jinja_env = Environment(
            loader=FileSystemLoader(str(self.templates_dir)),
            autoescape=select_autoescape(['html', 'xml']),
            trim_blocks=True,
            lstrip_blocks=True
        )

        # Add custom filters
        self.jinja_env.filters['date_format'] = self._date_format
        self.jinja_env.filters['grade_color'] = self._grade_color

        # Font configuration for WeasyPrint
        self.font_config = FontConfiguration()

        logger.info(f"PDFService initialized with templates from {self.templates_dir}")

    @staticmethod
    def _date_format(value: str, format_str: str = "%d.%m.%Y") -> str:
        """Formatiert Datum fuer deutsche Darstellung."""
        if not value:
            return ""
        try:
            dt = datetime.fromisoformat(value.replace("Z", "+00:00"))
            return dt.strftime(format_str)
        except (ValueError, AttributeError):
            return value

    @staticmethod
    def _grade_color(grade: str) -> str:
        """Gibt Farbe basierend auf Note zurueck."""
        grade_colors = {
            "1": "#27ae60",  # Gruen
            "2": "#2ecc71",  # Hellgruen
            "3": "#f1c40f",  # Gelb
            "4": "#e67e22",  # Orange
            "5": "#e74c3c",  # Rot
            "6": "#c0392b",  # Dunkelrot
            "A": "#27ae60",
            "B": "#2ecc71",
            "C": "#f1c40f",
            "D": "#e74c3c",
        }
        return grade_colors.get(str(grade), "#333333")

    def _get_base_css(self) -> str:
        """Gibt Basis-CSS fuer alle PDFs zurueck (delegiert an pdf_templates)."""
        return get_base_css()

    def generate_letter_pdf(self, data: LetterData) -> bytes:
        """
        Generiert PDF fuer Elternbrief.

        Args:
            data: LetterData mit allen Briefinformationen

        Returns:
            PDF als bytes
        """
        logger.info(f"Generating letter PDF for student: {data.student_name}")

        template = self._get_letter_template()
        html_content = template.render(
            data=data,
            generated_at=datetime.now().strftime("%d.%m.%Y %H:%M")
        )

        css = CSS(string=self._get_base_css(), font_config=self.font_config)
        pdf_bytes = HTML(string=html_content).write_pdf(
            stylesheets=[css],
            font_config=self.font_config
        )

        logger.info(f"Letter PDF generated: {len(pdf_bytes)} bytes")
        return pdf_bytes

    def generate_certificate_pdf(self, data: CertificateData) -> bytes:
        """
        Generiert PDF fuer Schulzeugnis.

        Args:
            data: CertificateData mit allen Zeugnisinformationen

        Returns:
            PDF als bytes
        """
        logger.info(f"Generating certificate PDF for: {data.student_name}")

        template = self._get_certificate_template()
        html_content = template.render(
            data=data,
            generated_at=datetime.now().strftime("%d.%m.%Y %H:%M")
        )

        css = CSS(string=self._get_base_css(), font_config=self.font_config)
        pdf_bytes = HTML(string=html_content).write_pdf(
            stylesheets=[css],
            font_config=self.font_config
        )

        logger.info(f"Certificate PDF generated: {len(pdf_bytes)} bytes")
        return pdf_bytes

    def generate_correction_pdf(self, data: CorrectionData) -> bytes:
        """
        Generiert PDF fuer Korrektur-Uebersicht.

        Args:
            data: CorrectionData mit allen Korrekturinformationen

        Returns:
            PDF als bytes
        """
        logger.info(f"Generating correction PDF for: {data.student.name}")

        template = self._get_correction_template()
        html_content = template.render(
            data=data,
            generated_at=datetime.now().strftime("%d.%m.%Y %H:%M")
        )

        css = CSS(string=self._get_base_css(), font_config=self.font_config)
        pdf_bytes = HTML(string=html_content).write_pdf(
            stylesheets=[css],
            font_config=self.font_config
        )

        logger.info(f"Correction PDF generated: {len(pdf_bytes)} bytes")
        return pdf_bytes

    def _get_letter_template(self):
        """Gibt Letter-Template zurueck (inline falls Datei nicht existiert)."""
        template_path = self.templates_dir / "letter.html"
        if template_path.exists():
            return self.jinja_env.get_template("letter.html")

        # Inline-Template als Fallback
        return self.jinja_env.from_string(get_letter_template_html())

    def _get_certificate_template(self):
        """Gibt Certificate-Template zurueck."""
        template_path = self.templates_dir / "certificate.html"
        if template_path.exists():
            return self.jinja_env.get_template("certificate.html")

        return self.jinja_env.from_string(get_certificate_template_html())

    def _get_correction_template(self):
        """Gibt Correction-Template zurueck."""
        template_path = self.templates_dir / "correction.html"
        if template_path.exists():
            return self.jinja_env.get_template("correction.html")

        return self.jinja_env.from_string(get_correction_template_html())


# Convenience functions for direct usage
_pdf_service: Optional[PDFService] = None


def get_pdf_service() -> PDFService:
    """Gibt Singleton-Instanz des PDF-Service zurueck."""
    global _pdf_service
    if _pdf_service is None:
        _pdf_service = PDFService()
    return _pdf_service


def generate_letter_pdf(data: Dict[str, Any]) -> bytes:
    """
    Convenience function zum Generieren eines Elternbrief-PDFs.

    Args:
        data: Dict mit allen Briefdaten

    Returns:
        PDF als bytes
    """
    service = get_pdf_service()

    # Convert dict to LetterData
    school_info = None
    if data.get("school_info"):
        school_info = SchoolInfo(**data["school_info"])

    letter_data = LetterData(
        recipient_name=data.get("recipient_name", ""),
        recipient_address=data.get("recipient_address", ""),
        student_name=data.get("student_name", ""),
        student_class=data.get("student_class", ""),
        subject=data.get("subject", ""),
        content=data.get("content", ""),
        date=data.get("date", datetime.now().strftime("%d.%m.%Y")),
        teacher_name=data.get("teacher_name", ""),
        teacher_title=data.get("teacher_title"),
        school_info=school_info,
        letter_type=data.get("letter_type", "general"),
        tone=data.get("tone", "professional"),
        legal_references=data.get("legal_references"),
        gfk_principles_applied=data.get("gfk_principles_applied")
    )

    return service.generate_letter_pdf(letter_data)


def generate_certificate_pdf(data: Dict[str, Any]) -> bytes:
    """
    Convenience function zum Generieren eines Zeugnis-PDFs.

    Args:
        data: Dict mit allen Zeugnisdaten

    Returns:
        PDF als bytes
    """
    service = get_pdf_service()

    school_info = None
    if data.get("school_info"):
        school_info = SchoolInfo(**data["school_info"])

    cert_data = CertificateData(
        student_name=data.get("student_name", ""),
        student_birthdate=data.get("student_birthdate", ""),
        student_class=data.get("student_class", ""),
        school_year=data.get("school_year", ""),
        certificate_type=data.get("certificate_type", "halbjahr"),
        subjects=data.get("subjects", []),
        attendance=data.get("attendance", {"days_absent": 0, "days_excused": 0, "days_unexcused": 0}),
        remarks=data.get("remarks"),
        class_teacher=data.get("class_teacher", ""),
        principal=data.get("principal", ""),
        school_info=school_info,
        issue_date=data.get("issue_date", datetime.now().strftime("%d.%m.%Y")),
        social_behavior=data.get("social_behavior"),
        work_behavior=data.get("work_behavior")
    )

    return service.generate_certificate_pdf(cert_data)


def generate_correction_pdf(data: Dict[str, Any]) -> bytes:
    """
    Convenience function zum Generieren eines Korrektur-PDFs.

    Args:
        data: Dict mit allen Korrekturdaten

    Returns:
        PDF als bytes
    """
    service = get_pdf_service()

    # Create StudentInfo from dict
    student = StudentInfo(
        student_id=data.get("student_id", "unknown"),
        name=data.get("student_name", data.get("name", "")),
        class_name=data.get("student_class", data.get("class_name", ""))
    )

    # Calculate percentage if not provided
    max_points = data.get("max_points", data.get("total_points", 0))
    achieved_points = data.get("achieved_points", 0)
    percentage = data.get("percentage", (achieved_points / max_points * 100) if max_points > 0 else 0.0)

    correction_data = CorrectionData(
        student=student,
        exam_title=data.get("exam_title", ""),
        subject=data.get("subject", ""),
        date=data.get("date", data.get("exam_date", "")),
        max_points=max_points,
        achieved_points=achieved_points,
        grade=data.get("grade", ""),
        percentage=percentage,
        corrections=data.get("corrections", []),
        teacher_notes=data.get("teacher_notes", data.get("teacher_comment", "")),
        ai_feedback=data.get("ai_feedback", ""),
        grade_distribution=data.get("grade_distribution"),
        class_average=data.get("class_average")
    )

    return service.generate_correction_pdf(correction_data)
