"""Persist CRA Art. 14 incident reports — schema-neutral (frozen DB).

Reuses the existing compliance_cra_documents table (doc_type='doc_incident_report'):
one row per incident, the full incident + per-stage submissions live in
generation_context (jsonb). No supersede chaining (unlike the assessment
snapshot store) — each incident is an independent, evolving record.
"""
import json
from typing import Optional

from sqlalchemy import text

from database import SessionLocal

DOC_TYPE = "doc_incident_report"


def _summary_md(inc: dict) -> str:
    return "\n".join([
        "# CRA-Meldung: {}".format(inc.get("summary", "(ohne Titel)")),
        "",
        "- Produkt: {} {}".format(inc.get("product_name", ""), inc.get("product_version", "")),
        "- Art: {} · Schwere: {}".format(inc.get("kind", ""), inc.get("severity", "")),
        "- Bekannt seit: {}".format(inc.get("aware_at", "")),
    ])


def create_incident(cra_project_id: str, tenant_id: str, incident: dict) -> dict:
    inc = dict(incident)
    inc.setdefault("submissions", {})       # stage_key -> {submitted_at, report}
    db = SessionLocal()
    try:
        row = db.execute(text("""
            INSERT INTO compliance_cra_documents
                (cra_project_id, tenant_id, doc_type, title, content_md, version,
                 requirements_coverage, generation_context, status)
            VALUES (CAST(:pid AS uuid), :tid, :dt, :title, :md, 1,
                    CAST('{}' AS jsonb), CAST(:ctx AS jsonb), 'open')
            RETURNING id, generated_at
        """), {"pid": cra_project_id, "tid": tenant_id, "dt": DOC_TYPE,
               "title": inc.get("summary", "CRA-Meldung")[:200],
               "md": _summary_md(inc), "ctx": json.dumps(inc)}).fetchone()
        db.commit()
        return {"id": str(row.id), "created_at": row.generated_at.isoformat(),
                "status": "open", **inc}
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()


def list_incidents(cra_project_id: str, tenant_id: str) -> list:
    db = SessionLocal()
    try:
        rows = db.execute(text("""
            SELECT id, status, generated_at, generation_context
            FROM compliance_cra_documents
            WHERE cra_project_id = CAST(:pid AS uuid) AND tenant_id = :tid AND doc_type = :dt
            ORDER BY generated_at DESC
        """), {"pid": cra_project_id, "tid": tenant_id, "dt": DOC_TYPE}).fetchall()
        out = []
        for r in rows:
            ctx = r.generation_context if isinstance(r.generation_context, dict) else {}
            out.append({"id": str(r.id), "status": r.status,
                        "created_at": r.generated_at.isoformat(), **ctx})
        return out
    finally:
        db.close()


def get_incident(incident_id: str, tenant_id: str) -> Optional[dict]:
    db = SessionLocal()
    try:
        r = db.execute(text("""
            SELECT id, status, generated_at, generation_context
            FROM compliance_cra_documents
            WHERE id = CAST(:iid AS uuid) AND tenant_id = :tid AND doc_type = :dt
        """), {"iid": incident_id, "tid": tenant_id, "dt": DOC_TYPE}).fetchone()
        if not r:
            return None
        ctx = r.generation_context if isinstance(r.generation_context, dict) else {}
        return {"id": str(r.id), "status": r.status,
                "created_at": r.generated_at.isoformat(), **ctx}
    finally:
        db.close()


def _save_ctx(db, incident_id: str, tenant_id: str, ctx: dict, status: str) -> None:
    db.execute(text("""
        UPDATE compliance_cra_documents
        SET generation_context = CAST(:ctx AS jsonb), status = :st, updated_at = NOW()
        WHERE id = CAST(:iid AS uuid) AND tenant_id = :tid AND doc_type = :dt
    """), {"ctx": json.dumps(ctx), "st": status, "iid": incident_id,
           "tid": tenant_id, "dt": DOC_TYPE})


def update_incident(incident_id: str, tenant_id: str, patch: dict) -> Optional[dict]:
    db = SessionLocal()
    try:
        r = db.execute(text("""
            SELECT status, generation_context FROM compliance_cra_documents
            WHERE id = CAST(:iid AS uuid) AND tenant_id = :tid AND doc_type = :dt
        """), {"iid": incident_id, "tid": tenant_id, "dt": DOC_TYPE}).fetchone()
        if not r:
            return None
        ctx = dict(r.generation_context if isinstance(r.generation_context, dict) else {})
        ctx.update({k: v for k, v in patch.items() if k != "submissions"})
        _save_ctx(db, incident_id, tenant_id, ctx, r.status)
        db.commit()
        return {"id": incident_id, "status": r.status, **ctx}
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()


def record_submission(incident_id: str, tenant_id: str, stage: str,
                      submitted_at: str, report: dict) -> Optional[dict]:
    """Mark a cascade stage as submitted (stores the ENISA export draft + ts)."""
    db = SessionLocal()
    try:
        r = db.execute(text("""
            SELECT generation_context FROM compliance_cra_documents
            WHERE id = CAST(:iid AS uuid) AND tenant_id = :tid AND doc_type = :dt
        """), {"iid": incident_id, "tid": tenant_id, "dt": DOC_TYPE}).fetchone()
        if not r:
            return None
        ctx = dict(r.generation_context if isinstance(r.generation_context, dict) else {})
        subs = dict(ctx.get("submissions") or {})
        subs[stage] = {"submitted_at": submitted_at, "report": report}
        ctx["submissions"] = subs
        status = "closed" if stage == "final" else "reporting"
        _save_ctx(db, incident_id, tenant_id, ctx, status)
        db.commit()
        return {"id": incident_id, "status": status, **ctx}
    except Exception:
        db.rollback()
        raise
    finally:
        db.close()
