from __future__ import annotations

from pathlib import Path
import logging

from sqlalchemy.orm import Session

from app.modules.orion.assets import ORION_ASSET_DIR
from app.modules.orion.components import (
    AttachmentComponent,
    ChecklistComponent,
    CoverComponent,
    CustomerComponent,
    DeviceComponent,
    DryingComponent,
    EnvironmentComponent,
    EquipmentComponent,
    LoadingComponent,
    MeasurementComponent,
    ProgramComponent,
    RecommendationComponent,
    ReportComponent,
    StaticTextComponent,
    SummaryComponent,
    TocComponent,
)
from app.modules.orion.context import OrionContextBuilder, ReportContext
from app.modules.orion.templates.report import render_document

logger = logging.getLogger(__name__)


class OrionReportService:
    def __init__(self, session: Session, generated_dir: Path | None = None) -> None:
        self.session = session
        self.generated_dir = generated_dir or Path("/app/reports")

    def render_html(self, validation_id: str) -> str:
        context = OrionContextBuilder(self.session, self.generated_dir).build(validation_id)
        components = self._components()
        chapters = [component.render(context) for component in components]
        return render_document(context, chapters)

    def render_pdf(self, validation_id: str) -> Path:
        from weasyprint import HTML

        context = OrionContextBuilder(self.session, self.generated_dir).build(validation_id)
        output_path = context.generated_dir / f"{context.validation.report_number}.pdf"
        html = self.render_html(validation_id)
        HTML(string=html, base_url=str(ORION_ASSET_DIR)).write_pdf(output_path)
        self._append_pdf_attachments(context, output_path)
        return output_path

    def _components(self) -> list[ReportComponent]:
        chapters: list[ReportComponent] = [
            StaticTextComponent("bq", "1 Funktionsqualifikation (BQ)", "nicht erfasst"),
            StaticTextComponent("bq-goal", "1.1 Anlass und Ziel der Prüfung", block_key="bq_goal"),
            StaticTextComponent("legal", "1.2 Gesetzliche Grundlagen", block_key="legal"),
            DeviceComponent(),
            StaticTextComponent("performance", "1.4 Leistungsüberprüfung", block_key="performance"),
            ChecklistComponent(),
            StaticTextComponent("documentation", "1.6 Dokumentation / Kontrolle"),
            StaticTextComponent("work-instructions", "1.7 Arbeitsanweisungen"),
            EnvironmentComponent(),
            StaticTextComponent("batch-control", "1.9 Chargenkontrolle"),
            ProgramComponent(),
            LoadingComponent(),
            StaticTextComponent("reference-load", "1.12 Referenzbeladung Sterilisator"),
            StaticTextComponent("equipment", "2 Eingesetzte Prüfmittel"),
            EquipmentComponent(),
            StaticTextComponent("equipment-thermo", "2.2 Prüfmittel zur thermoelektrischen Untersuchung"),
            StaticTextComponent("configuration", "2.3 Prüfkonfiguration"),
            StaticTextComponent("lq", "3 Leistungsqualifikation (LQ)"),
            StaticTextComponent("thermo-tests", "3.1 Leistungsbeurteilung – Thermoelektrische Prüfungen"),
            MeasurementComponent(),
            StaticTextComponent("run-1", "3.2 Standardbeladung – Testlauf 1"),
            StaticTextComponent("test-1", "3.2.1 Test 1"),
            StaticTextComponent("run-2", "3.3 Standardbeladung – Testlauf 2"),
            StaticTextComponent("test-2", "3.3.1 Test 2"),
            StaticTextComponent("run-3", "3.4 Standardbeladung – Testlauf 3"),
            StaticTextComponent("test-3", "3.4.1 Test 3"),
            StaticTextComponent("results", "4 Ergebnisse der Validierung"),
            StaticTextComponent("results-vacuum", "4.1 Vakuumtest"),
            StaticTextComponent("results-runs", "4.1.2 Testläufe 1 bis 3"),
            DryingComponent(),
            RecommendationComponent(),
            StaticTextComponent("appendix", "5 Anhang"),
            AttachmentComponent(),
            StaticTextComponent("winlog", "5.1 Winlog-Auswertungen"),
            StaticTextComponent("release-docs", "5.2 Freigabedokumentation / Routineprüfungen"),
            StaticTextComponent("indicators", "5.3 Nachweis der umgeschlagenen Indikatoren"),
            StaticTextComponent("cycles", "6 Programmabläufe / Zyklen"),
            StaticTextComponent("practice-certificates", "6.1 Zertifikate Praxis"),
            StaticTextComponent("risk", "7 Risikoeinstufung nach RKI"),
            StaticTextComponent("closing-talk", "7.1 Abschlussgespräch"),
            StaticTextComponent("certificates", "8. Zertifikate"),
            StaticTextComponent("calibration-certificates", "9. Werkskalibrierzertifikate Sensoren"),
        ]
        return [CoverComponent(), SummaryComponent(), TocComponent(chapters), CustomerComponent(), *chapters]

    def _append_pdf_attachments(self, context: ReportContext, output_path: Path) -> None:
        pdf_paths = []
        for item in context.validation.attachments or []:
            filename = str(item.get("filename") or "")
            content_type = str(item.get("content_type") or "")
            if not filename.lower().endswith(".pdf") and content_type != "application/pdf":
                continue
            storage_path = item.get("storage_path")
            if storage_path and Path(str(storage_path)).exists():
                pdf_paths.append(Path(str(storage_path)))
        if not pdf_paths:
            return
        try:
            from pypdf import PdfReader, PdfWriter

            writer = PdfWriter()
            for page in PdfReader(str(output_path)).pages:
                writer.add_page(page)
            for pdf_path in pdf_paths:
                try:
                    for page in PdfReader(str(pdf_path)).pages:
                        writer.add_page(page)
                except Exception:
                    logger.exception("Could not append attachment PDF %s", pdf_path)
            with output_path.open("wb") as handle:
                writer.write(handle)
        except Exception:
            logger.exception("Could not merge Orion PDF attachments for validation %s", context.validation.id)
