"""Generate dossier gap and readiness reports from stored metadata."""

from __future__ import annotations

from collections import defaultdict
from typing import Any

from app.modules.dossier.application.dossier_rules import get_readiness_rules, get_stage_requirements
from app.modules.core.application.qdrant_store import QdrantStore


class DossierReportService:
    """Build gap-analysis and readiness reports for a project."""

    def __init__(self, qdrant_store: QdrantStore) -> None:
        self._qdrant_store = qdrant_store
        self._stage_requirements = get_stage_requirements()
        self._readiness_rules = get_readiness_rules()

    def build_project_report(self, project_code: str) -> dict[str, Any]:
        """Return a combined gap and readiness report for the given project."""
        source = "qdrant"
        used_fallback = False
        message = (
            "Dossier readiness report được tổng hợp từ metadata đã ingest trong Qdrant."
        )

        try:
            documents = self._load_project_documents(project_code)
        except Exception as exc:
            documents = []
            source = "fallback"
            used_fallback = True
            message = f"Không thể tải dossier documents từ Qdrant: {exc}; trả báo cáo rỗng an toàn."

        present_by_stage: dict[str, list[str]] = defaultdict(list)
        present_doc_types: set[str] = set()
        document_index: dict[str, dict[str, Any]] = {}

        for item in documents:
            metadata = dict(item.get("metadata", {}) or {})
            doc_stage = str(metadata.get("doc_stage", "") or "")
            document_type = str(metadata.get("document_type", "") or "")
            source_filename = str(metadata.get("source_filename", "") or "")

            if (
                doc_stage
                and document_type
                and document_type not in present_by_stage[doc_stage]
            ):
                present_by_stage[doc_stage].append(document_type)

            if document_type:
                present_doc_types.add(document_type)

            if document_type and document_type not in document_index:
                document_index[document_type] = {
                    "document_type": document_type,
                    "source_filename": source_filename,
                    "doc_stage": doc_stage,
                    "doc_family": metadata.get("doc_family"),
                    "task_type": metadata.get("task_type"),
                    "readiness_weight": metadata.get("readiness_weight", 0.0),
                }

        missing_by_stage: dict[str, list[dict[str, Any]]] = {}
        critical_missing: list[dict[str, Any]] = []

        for stage, requirements in self._stage_requirements.items():
            stage_missing: list[dict[str, Any]] = []
            for requirement in requirements:
                document_type = requirement["document_type"]
                if document_type not in present_doc_types:
                    stage_missing.append(requirement)
                    if requirement.get("critical"):
                        critical_missing.append(
                            {
                                "doc_stage": stage,
                                "document_type": document_type,
                                "label": requirement["label"],
                            }
                        )
            missing_by_stage[stage] = stage_missing

        readiness = self._build_readiness(present_doc_types)

        return {
            "project_code": project_code,
            "source": source,
            "used_fallback": used_fallback,
            "message": message,
            "documents_present": {
                stage: sorted(doc_types)
                for stage, doc_types in sorted(present_by_stage.items())
            },
            "document_index": document_index,
            "documents_missing": {
                stage: [
                    {
                        "document_type": item["document_type"],
                        "label": item["label"],
                        "critical": item["critical"],
                    }
                    for item in items
                ]
                for stage, items in missing_by_stage.items()
            },
            "critical_missing": critical_missing,
            "readiness": readiness,
            "summary": self._build_summary(readiness, critical_missing),
        }

    def _load_project_documents(self, project_code: str) -> list[dict[str, Any]]:
        """Load all matching project documents from Qdrant."""
        results = self._qdrant_store.scroll(
            limit=500,
            filters={"project_code": project_code},
        )
        normalized: list[dict[str, Any]] = []
        seen_doc_types: set[str] = set()

        for item in results:
            metadata = dict(item.get("metadata", {}) or {})
            document_type = str(metadata.get("document_type", "") or "")
            if not document_type or document_type in seen_doc_types:
                continue
            seen_doc_types.add(document_type)
            normalized.append(item)

        return normalized

    def _build_readiness(
        self, present_doc_types: set[str]
    ) -> dict[str, dict[str, Any]]:
        """Calculate readiness state for key business stages."""
        output: dict[str, dict[str, Any]] = {}

        for stage, required_doc_types in self._readiness_rules.items():
            missing = [
                doc_type
                for doc_type in required_doc_types
                if doc_type not in present_doc_types
            ]
            total = len(required_doc_types)
            available = total - len(missing)
            score = round(available / total, 2) if total else 0.0

            if not missing:
                status = "ready"
            elif available == 0:
                status = "blocked"
            else:
                status = "partial"

            output[stage] = {
                "status": status,
                "score": score,
                "required_count": total,
                "available_count": available,
                "missing_count": len(missing),
                "blocking_items": missing,
            }

        return output

    def _build_summary(
        self,
        readiness: dict[str, dict[str, Any]],
        critical_missing: list[dict[str, Any]],
    ) -> dict[str, Any]:
        """Build a short operational summary."""
        return {
            "contracting_status": readiness.get("contracting", {}).get(
                "status", "unknown"
            ),
            "payment_status": readiness.get("payment", {}).get("status", "unknown"),
            "finalization_status": readiness.get("finalization", {}).get(
                "status", "unknown"
            ),
            "critical_missing_count": len(critical_missing),
        }
