from __future__ import annotations

from io import BytesIO

from docx import Document
from openpyxl import load_workbook

from grantflow.exporters.excel_builder import build_xlsx_from_logframe
from grantflow.exporters.word_builder import build_docx_from_toc


def _eu_min_toc() -> dict:
    return {
        "toc": {
            "overall_objective": {"objective_id": "OO1", "title": "Digital governance", "rationale": "EU fit"},
            "specific_objectives": [{"objective_id": "SO1", "title": "Service quality", "rationale": "Delivery"}],
            "expected_outcomes": [
                {"outcome_id": "OUT1", "title": "Citizen trust", "expected_change": "Higher confidence"}
            ],
        }
    }


def test_docx_autofills_eu_safeguarding_annex_from_critic_findings():
    toc = _eu_min_toc()
    findings = [
        {
            "code": "EU_SAFE_001",
            "section": "safeguarding",
            "message": "Safeguarding protocol is missing for partner-facing activities.",
            "fix_hint": "Add referral pathway and incident-response SOP in annex.",
            "severity": "high",
        },
        {
            "code": "EU_RISK_001",
            "section": "risk_register",
            "message": "Risk controls are not clearly assigned.",
            "severity": "medium",
        },
    ]

    doc = Document(BytesIO(build_docx_from_toc(toc, "eu", critic_findings=findings, include_diagnostics=False)))
    text = "\n".join(p.text for p in doc.paragraphs)

    assert "Risk & Safeguarding Annex" in text
    assert "referral pathway" in text.lower()
    assert "risk register entries" in text.lower()


def test_xlsx_autofills_eu_safeguarding_annex_from_critic_findings():
    toc = _eu_min_toc()
    findings = [
        {
            "code": "EU_COMP_002",
            "section": "compliance",
            "message": "Risk control plan is incomplete for field implementation.",
            "fix_suggestion": "Document do-no-harm controls and escalation owner in annex.",
            "severity": "medium",
        }
    ]

    content = build_xlsx_from_logframe({"indicators": []}, "eu", toc_draft=toc, critic_findings=findings)
    wb = load_workbook(BytesIO(content))
    rows = list(wb["EU_Assumptions_Risks"].iter_rows(values_only=True))

    assert any((r and r[0] == "Safeguarding Annex") for r in rows[1:])
    assert any((r and "do-no-harm" in str(r[1]).lower()) for r in rows[1:])


def test_docx_keeps_existing_eu_safeguarding_annex_when_present():
    toc = _eu_min_toc()
    toc["toc"]["safeguarding_annex"] = ["Keep existing annex content."]
    findings = [
        {
            "code": "EU_SAFE_010",
            "section": "safeguarding",
            "message": "Missing protocol",
            "fix_hint": "Duplicate line should not replace explicit annex.",
        }
    ]

    doc = Document(BytesIO(build_docx_from_toc(toc, "eu", critic_findings=findings, include_diagnostics=False)))
    text = "\n".join(p.text for p in doc.paragraphs)
    assert "Keep existing annex content." in text
    assert "Duplicate line should not replace explicit annex." not in text


def test_xlsx_deduplicates_inferred_eu_annex_items_from_repeated_findings():
    toc = _eu_min_toc()
    findings = [
        {
            "code": "EU_SAFE_020",
            "section": "safeguarding",
            "message": "Safeguarding protocol missing.",
            "fix_hint": "Add referral pathway and incident-response SOP in annex.",
        },
        {
            "code": "EU_SAFE_021",
            "section": "safeguarding",
            "message": "Safeguarding protocol missing again.",
            "fix_hint": "Add referral pathway and incident-response SOP in annex.",
        },
    ]

    content = build_xlsx_from_logframe({"indicators": []}, "eu", toc_draft=toc, critic_findings=findings)
    wb = load_workbook(BytesIO(content))
    rows = [r for r in wb["EU_Assumptions_Risks"].iter_rows(values_only=True) if r and r[0] == "Safeguarding Annex"]
    annex_items = [str(r[1]) for r in rows]
    assert annex_items.count("Add referral pathway and incident-response SOP in annex.") == 1
