from __future__ import annotations

"""Blocker extraction and construction from session data."""

from typing import Any

from app.models.schemas import CompanyOperationalBlockedItem


class BlockersBuilderMixin:
    """Blocker extraction and construction mixin."""

    def _build_blockers_from_session(
        self, session: dict[str, Any]
    ) -> list[CompanyOperationalBlockedItem]:
        """Map blocking findings into blocker board items."""
        items: list[CompanyOperationalBlockedItem] = []
        project_code = str(session.get("project_code") or "")
        project_name = str(session.get("project_name") or "")
        review_id = str(session.get("review_id") or "")

        for finding in self._ensure_list(session.get("findings")):
            assignments = self._ensure_list(finding.get("assignments"))
            primary_assignment = assignments[0] if assignments else {}
            blocker_reasons = self._collect_blocker_reasons(
                session=session, finding=finding
            )

            if bool(finding.get("is_blocking")):
                items.append(
                    CompanyOperationalBlockedItem(
                        project_code=project_code or None,
                        project_name=project_name or None,
                        review_session_id=review_id or None,
                        finding_code=str(finding.get("finding_code") or "") or None,
                        employee_code=primary_assignment.get("assigned_employee_code"),
                        department_code=finding.get("responsible_department_code")
                        or primary_assignment.get("assigned_department_code"),
                        title=str(finding.get("title") or "Blocking dossier finding"),
                        status=str(finding.get("status") or "open"),
                        owner=primary_assignment.get("assigned_employee_name")
                        or primary_assignment.get("assigned_employee_code"),
                        reason=finding.get("description")
                        or finding.get("resolution_note"),
                        source_type="dossier_review_finding",
                        reference_id=str(finding.get("finding_id") or "") or None,
                        due_date=primary_assignment.get("due_date")
                        or finding.get("due_date"),
                        metadata=self._merge_metadata(
                            finding.get("metadata"),
                            {
                                "supplement_status": finding.get("supplement_status"),
                                "severity": finding.get("severity"),
                                "impact_level": finding.get("impact_level"),
                                "blocker_reasons": blocker_reasons,
                            },
                        ),
                    )
                )

            for index, blocker_action in enumerate(
                self._collect_post_completion_blockers(
                    session=session, finding=finding
                ),
                start=1,
            ):
                items.append(
                    CompanyOperationalBlockedItem(
                        project_code=project_code or None,
                        project_name=project_name or None,
                        review_session_id=review_id or None,
                        finding_code=str(finding.get("finding_code") or "") or None,
                        employee_code=str(
                            blocker_action.get("owner_employee_code") or ""
                        )
                        or None,
                        department_code=blocker_action.get("department_code")
                        or finding.get("responsible_department_code"),
                        title=str(
                            blocker_action.get("title")
                            or finding.get("title")
                            or "Post-review blocker"
                        ),
                        status=str(blocker_action.get("status") or "pending"),
                        owner=blocker_action.get("owner_employee_code")
                        or blocker_action.get("department_code"),
                        reason=blocker_action.get("reason")
                        or blocker_action.get("description"),
                        source_type=str(
                            blocker_action.get("source_type")
                            or "dossier_review_follow_up"
                        ),
                        reference_id=str(
                            blocker_action.get("reference_id") or f"{review_id}:{index}"
                        )
                        or None,
                        due_date=blocker_action.get("due_date"),
                        metadata=self._merge_metadata(
                            blocker_action.get("metadata"),
                            {
                                "finding_id": finding.get("finding_id"),
                                "finding_status": finding.get("status"),
                                "trigger_phase": blocker_action.get("trigger_phase"),
                            },
                        ),
                    )
                )

        return items

    def _collect_post_completion_blockers(
        self,
        *,
        session: dict[str, Any],
        finding: dict[str, Any],
    ) -> list[dict[str, Any]]:
        """Collect unresolved post-completion follow-up actions that should appear as blockers."""
        items: list[dict[str, Any]] = []

        follow_ups = self._collect_post_close_actions(session=session, finding=finding)
        follow_ups.extend(
            self._collect_post_verification_actions(session=session, finding=finding)
        )

        for action in follow_ups:
            if not self._is_blocking_follow_up(action):
                continue
            # Gắn source_type ổn định để downstream dễ dùng.
            items.append(
                self._merge_metadata(
                    action,
                    {
                        "source_type": action.get("source_type")
                        or "dossier_review_follow_up",
                    },
                )
            )

        return items

    def _collect_blocker_reasons(
        self, *, session: dict[str, Any], finding: dict[str, Any]
    ) -> list[str]:
        """Collect human-readable blocker reasons from metadata and action payloads."""
        reasons: list[str] = []
        sources = [
            self._ensure_dict(finding.get("metadata")),
            self._ensure_dict(session.get("metadata")),
        ]

        for source in sources:
            for key in ("blocked_reasons", "blocking_reasons"):
                value = source.get(key)
                if isinstance(value, list):
                    reasons.extend(
                        str(item) for item in value if str(item or "").strip()
                    )
                elif isinstance(value, str) and value.strip():
                    reasons.append(value.strip())

        for action in self._ensure_list(session.get("actions")):
            payload = self._ensure_dict(action.get("action_payload"))
            if not self._action_matches_finding(
                action_payload=payload, finding=finding
            ):
                continue
            for key in ("blocked_reasons", "blocking_reasons"):
                value = payload.get(key)
                if isinstance(value, list):
                    reasons.extend(
                        str(item) for item in value if str(item or "").strip()
                    )
                elif isinstance(value, str) and value.strip():
                    reasons.append(value.strip())

        return reasons

    def _is_blocking_follow_up(item: dict[str, Any]) -> bool:
        """Return True when a follow-up item should be surfaced as a blocker."""
        status = str(item.get("status") or "").strip().lower()
        if status in {
            "completed",
            "closed",
            "resolved",
            "verified",
            "accepted",
            "done",
        }:
            return False

        if bool(item.get("blocking")) or bool(item.get("is_blocking")):
            return True

        normalized_priority = str(item.get("priority") or "").strip().lower()
        normalized_type = str(item.get("action_type") or "").strip().lower()
        return normalized_priority in {"high", "critical"} or "block" in normalized_type
