"""CRA Article 14 incident-reporting (Meldewesen) endpoints.

The 24h/72h/14d cascade to ENISA's SRP. Thin handlers delegate to the pure
cra_meldewesen logic + the schema-neutral cra_incident_store. There is no live
ENISA API — submissions store a downloadable export draft.
"""
from datetime import datetime, timezone
from typing import Optional

from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel

from compliance.services import cra_incident_store as store
from compliance.services.cra_meldewesen import (
    STAGES, SEVERITIES, KINDS, REPORTING_ACTIVE_FROM,
    compute_deadlines, next_open_stage, build_enisa_report, report_completeness,
)
from .tenant_utils import get_tenant_id

router = APIRouter(prefix="/v1/cra", tags=["cra-meldewesen"])


class IncidentCreate(BaseModel):
    cra_project_id: str
    summary: str = ""
    product_name: str = ""
    product_version: str = ""
    manufacturer: str = ""
    kind: str = "exploited_vulnerability"
    severity: str = "high"
    aware_at: str = ""
    contact: str = ""
    impact: str = ""
    affected_components: str = ""
    exploitation_status: str = ""
    iocs: str = ""
    mitigations: str = ""
    personal_data_affected: bool = False
    root_cause: str = ""
    corrective_measures: str = ""
    patch_available: bool = False
    patch_reference: str = ""
    lessons_learned: str = ""


class IncidentPatch(BaseModel):
    summary: Optional[str] = None
    impact: Optional[str] = None
    affected_components: Optional[str] = None
    exploitation_status: Optional[str] = None
    iocs: Optional[str] = None
    mitigations: Optional[str] = None
    personal_data_affected: Optional[bool] = None
    root_cause: Optional[str] = None
    corrective_measures: Optional[str] = None
    patch_available: Optional[bool] = None
    patch_reference: Optional[str] = None
    lessons_learned: Optional[str] = None


def _enrich(inc: dict) -> dict:
    """Attach computed deadlines + next open stage (derived, never stored)."""
    subs = {k: v.get("submitted_at") for k, v in (inc.get("submissions") or {}).items()}
    deadlines = compute_deadlines(inc.get("aware_at", ""), subs)
    return {**inc, "deadlines": deadlines, "next_stage": next_open_stage(deadlines)}


@router.get("/incidents/meta")
async def incident_meta() -> dict:
    return {"stages": STAGES, "severities": SEVERITIES, "kinds": KINDS,
            "reporting_active_from": REPORTING_ACTIVE_FROM}


@router.post("/incidents")
async def create_incident(body: IncidentCreate, tenant_id: str = Depends(get_tenant_id)) -> dict:
    data = body.model_dump()
    pid = data.pop("cra_project_id")
    if not data.get("aware_at"):
        data["aware_at"] = datetime.now(timezone.utc).isoformat()
    return _enrich(store.create_incident(pid, tenant_id, data))


@router.get("/incidents")
async def list_incidents(cra_project_id: str, tenant_id: str = Depends(get_tenant_id)) -> dict:
    items = [_enrich(i) for i in store.list_incidents(cra_project_id, tenant_id)]
    return {"incidents": items, "count": len(items)}


@router.get("/incidents/{incident_id}")
async def get_incident(incident_id: str, tenant_id: str = Depends(get_tenant_id)) -> dict:
    inc = store.get_incident(incident_id, tenant_id)
    if not inc:
        raise HTTPException(status_code=404, detail="Meldung nicht gefunden")
    return _enrich(inc)


@router.patch("/incidents/{incident_id}")
async def update_incident(incident_id: str, body: IncidentPatch,
                          tenant_id: str = Depends(get_tenant_id)) -> dict:
    patch = {k: v for k, v in body.model_dump().items() if v is not None}
    inc = store.update_incident(incident_id, tenant_id, patch)
    if not inc:
        raise HTTPException(status_code=404, detail="Meldung nicht gefunden")
    return _enrich(inc)


@router.get("/incidents/{incident_id}/export/{stage}")
async def export_stage(incident_id: str, stage: str,
                       tenant_id: str = Depends(get_tenant_id)) -> dict:
    inc = store.get_incident(incident_id, tenant_id)
    if not inc:
        raise HTTPException(status_code=404, detail="Meldung nicht gefunden")
    try:
        report = build_enisa_report(inc, stage)
    except ValueError:
        raise HTTPException(status_code=400, detail="Unbekannte Meldestufe")
    return {"report": report, "completeness": report_completeness(inc, stage)}


@router.post("/incidents/{incident_id}/submit/{stage}")
async def submit_stage(incident_id: str, stage: str,
                       tenant_id: str = Depends(get_tenant_id)) -> dict:
    inc = store.get_incident(incident_id, tenant_id)
    if not inc:
        raise HTTPException(status_code=404, detail="Meldung nicht gefunden")
    try:
        report = build_enisa_report(inc, stage)
    except ValueError:
        raise HTTPException(status_code=400, detail="Unbekannte Meldestufe")
    ts = datetime.now(timezone.utc).isoformat()
    updated = store.record_submission(incident_id, tenant_id, stage, ts, report)
    return _enrich(updated)
