from __future__ import annotations

from datetime import date
from pathlib import Path
from xml.sax.saxutils import escape
import zipfile

from django.conf import settings
from django.utils import timezone

from agent_core.governance import load_governance_config
from apps.documents.services import create_export_record


def generate_registration_export(*, batch, conversation, upstream_summary: dict | None = None) -> dict:
    """
    基于当前会话上下文生成最小可下载的 Word 导出结果。

    这里故意保持为 Django 服务层职责：
    - 根据风险结果判断正式版/草稿版
    - 选择治理台中启用的模板摘要
    - 生成离线可演示的 `.docx` 文件与下载链接
    """
    upstream_summary = upstream_summary or {}
    template_mapping = _resolve_template_mapping()
    blocked_items = _collect_blocked_items(upstream_summary)
    can_export_formally = _can_export_formally(upstream_summary, blocked_items)
    export_mode = "formal" if can_export_formally else "draft"
    export_status = "completed" if can_export_formally else "draft_only"
    relative_path = _build_relative_export_path(batch.batch_id, export_mode)
    absolute_path = Path(settings.MEDIA_ROOT) / relative_path
    absolute_path.parent.mkdir(parents=True, exist_ok=True)

    fillable_items = _build_fillable_items(batch, conversation)
    filled_fields = _build_filled_fields(fillable_items)
    blocked_fields = _build_blocked_fields(blocked_items)
    _write_minimal_docx(
        absolute_path,
        product_name=batch.product_name or conversation.product_name or "未命名资料包",
        batch_id=batch.batch_id,
        export_mode=export_mode,
        summary=upstream_summary.get("summary", ""),
        fillable_items=fillable_items,
        blocked_items=blocked_items,
        template_mapping=template_mapping,
    )

    file_name = absolute_path.name
    download_url = f"/{settings.MEDIA_URL.strip('/')}/{relative_path.as_posix()}"
    summary = (
        "已生成正式版导出文件。"
        if can_export_formally
        else "已生成草稿导出文件，正式版仍被风险项阻断。"
    )
    report = {
        "output_type": "registration_word_export_report",
        "summary": summary,
        "template_name": template_mapping["template_name"],
        "template_version": template_mapping["version"],
        "export_status": export_status,
        "draft_export_status": "completed",
        "formal_export_status": "completed" if can_export_formally else "blocked",
        "can_export_formally": can_export_formally,
        "fillable_items": fillable_items,
        "filled_fields": filled_fields,
        "fillable_field_count": len(fillable_items),
        "filled_field_count": len(filled_fields),
        "blocked_items": blocked_items,
        "blocked_fields": blocked_fields,
        "blocked_field_count": len(blocked_fields),
        "manual_review_field_count": len(blocked_fields),
        "layout_check_status": "passed",
        "download_url": download_url,
        "output_file": {
            "file_name": file_name,
            "relative_path": relative_path.as_posix(),
            "absolute_path": str(absolute_path),
            "export_mode": export_mode,
            "output_version": export_mode,
            "generated_at": timezone.now().isoformat(),
        },
    }
    create_export_record(
        batch=batch,
        conversation_id=conversation.conversation_id,
        product_name=batch.product_name or conversation.product_name,
        template_name=report["template_name"],
        template_version=report["template_version"],
        export_mode=export_mode,
        output_type=report["output_type"],
        file_name=file_name,
        relative_path=relative_path.as_posix(),
        download_url=download_url,
    )
    return report


def update_conversation_with_export_report(conversation, export_report: dict) -> None:
    latest_summary = dict(conversation.latest_summary or {})
    previous_structured_output = latest_summary.get("structured_output") or {}
    if previous_structured_output.get("output_type") != "registration_word_export_report":
        latest_summary["upstream_structured_output"] = previous_structured_output
    latest_summary["structured_output"] = export_report
    latest_summary["answer"] = export_report.get("summary", "")
    latest_summary["status"] = "success"
    conversation.latest_summary = latest_summary
    conversation.node_results = _update_word_export_node(conversation.node_results, export_report)
    conversation.save(update_fields=["latest_summary", "node_results", "updated_at"])


def _resolve_template_mapping() -> dict:
    governance_config = load_governance_config()
    for item in governance_config["template_mappings"]:
        if item.get("status") == "启用":
            return item
    return {
        "template_name": "注册证导出模板",
        "version": "V1.0",
        "field_mapping_summary": "产品名称 / 批次号 / 风险结论",
    }


def _collect_blocked_items(upstream_summary: dict) -> list[str]:
    blocked_items = []
    for item in upstream_summary.get("manual_review_items") or []:
        if isinstance(item, str) and item.strip():
            blocked_items.append(item.strip())
    for item in upstream_summary.get("risk_items") or []:
        if isinstance(item, dict):
            title = (item.get("title") or item.get("issue") or "").strip()
            if title:
                blocked_items.append(title)
    unique_items = []
    for item in blocked_items:
        if item not in unique_items:
            unique_items.append(item)
    return unique_items


def _can_export_formally(upstream_summary: dict, blocked_items: list[str]) -> bool:
    pass_status = upstream_summary.get("pass_status")
    if pass_status in {"blocked", "failed", "review_required", "manual_review"}:
        return False
    highest_risk_level = str(upstream_summary.get("highest_risk_level", "")).lower()
    if highest_risk_level == "high":
        return False
    return not blocked_items


def _build_fillable_items(batch, conversation) -> list[dict]:
    return [
        {
            "placeholder": "{{ product_name }}",
            "field_name": "产品名称",
            "field_value": batch.product_name,
            "source": "资料包主信息",
            "fill_status": "filled",
            "required": True,
        },
        {
            "placeholder": "{{ batch_id }}",
            "field_name": "批次号",
            "field_value": batch.batch_id,
            "source": "资料包主信息",
            "fill_status": "filled",
            "required": True,
        },
        {
            "placeholder": "{{ conversation_id }}",
            "field_name": "会话编号",
            "field_value": conversation.conversation_id,
            "source": "会话主信息",
            "fill_status": "filled",
            "required": True,
        },
        {
            "placeholder": "{{ file_count }}",
            "field_name": "文件数",
            "field_value": str(batch.file_count),
            "source": "资料包统计",
            "fill_status": "filled",
            "required": False,
        },
        {
            "placeholder": "{{ page_count }}",
            "field_name": "页数",
            "field_value": str(batch.page_count),
            "source": "资料包统计",
            "fill_status": "filled",
            "required": False,
        },
    ]


def _build_filled_fields(fillable_items: list[dict]) -> list[dict]:
    return [
        {
            "placeholder": item["placeholder"],
            "field_name": item["field_name"],
            "field_value": item["field_value"],
            "source": item["source"],
            "fill_status": item["fill_status"],
            "required": item["required"],
        }
        for item in fillable_items
    ]


def _build_blocked_fields(blocked_items: list[str]) -> list[dict]:
    return [
        {
            "field_name": item,
            "block_reason": "待人工复核",
            "risk_source": "registration_risk_report",
        }
        for item in blocked_items
    ]


def _build_relative_export_path(batch_id: str, export_mode: str) -> Path:
    file_name = f"{batch_id}-{export_mode}.docx"
    return Path("exports") / date.today().strftime("%Y%m%d") / file_name


def _update_word_export_node(node_results: list[dict], export_report: dict) -> list[dict]:
    updated_nodes = []
    export_status = export_report.get("export_status")
    node_status = "已完成" if export_status == "completed" else "待复核"
    for node in node_results or []:
        current = dict(node)
        if current.get("label") == "Word 回填导出":
            current["status"] = node_status
            current["summary"] = export_report.get("summary", "")
        updated_nodes.append(current)
    return updated_nodes


def _write_minimal_docx(
    output_path: Path,
    *,
    product_name: str,
    batch_id: str,
    export_mode: str,
    summary: str,
    fillable_items: list[dict],
    blocked_items: list[str],
    template_mapping: dict,
) -> None:
    document_lines = [
        f"注册审核导出文件（{'正式版' if export_mode == 'formal' else '草稿版'}）",
        f"产品名称：{product_name}",
        f"批次号：{batch_id}",
        f"模板：{template_mapping.get('template_name', '')} {template_mapping.get('version', '')}".strip(),
        f"风险摘要：{summary or '无'}",
        "回填字段：",
    ]
    document_lines.extend(
        f"- {item['field_name']}：{item['field_value']}" for item in fillable_items
    )
    if blocked_items:
        document_lines.append("阻断项：")
        document_lines.extend(f"- {item}" for item in blocked_items)
    else:
        document_lines.append("阻断项：无")

    document_xml = _build_document_xml(document_lines)
    with zipfile.ZipFile(output_path, "w", compression=zipfile.ZIP_DEFLATED) as archive:
        archive.writestr("[Content_Types].xml", _content_types_xml())
        archive.writestr("_rels/.rels", _root_rels_xml())
        archive.writestr("word/document.xml", document_xml)
        archive.writestr("word/_rels/document.xml.rels", _document_rels_xml())


def _build_document_xml(lines: list[str]) -> str:
    paragraphs = "".join(
        f"<w:p><w:r><w:t xml:space='preserve'>{escape(line)}</w:t></w:r></w:p>" for line in lines
    )
    return (
        "<?xml version='1.0' encoding='UTF-8' standalone='yes'?>"
        "<w:document xmlns:w='http://schemas.openxmlformats.org/wordprocessingml/2006/main'>"
        "<w:body>"
        f"{paragraphs}"
        "<w:sectPr/>"
        "</w:body>"
        "</w:document>"
    )


def _content_types_xml() -> str:
    return (
        "<?xml version='1.0' encoding='UTF-8'?>"
        "<Types xmlns='http://schemas.openxmlformats.org/package/2006/content-types'>"
        "<Default Extension='rels' ContentType='application/vnd.openxmlformats-package.relationships+xml'/>"
        "<Default Extension='xml' ContentType='application/xml'/>"
        "<Override PartName='/word/document.xml' "
        "ContentType='application/vnd.openxmlformats-officedocument.wordprocessingml.document.main+xml'/>"
        "</Types>"
    )


def _root_rels_xml() -> str:
    return (
        "<?xml version='1.0' encoding='UTF-8'?>"
        "<Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'>"
        "<Relationship Id='rId1' "
        "Type='http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument' "
        "Target='word/document.xml'/>"
        "</Relationships>"
    )


def _document_rels_xml() -> str:
    return (
        "<?xml version='1.0' encoding='UTF-8'?>"
        "<Relationships xmlns='http://schemas.openxmlformats.org/package/2006/relationships'/>"
    )
