from __future__ import annotations

from typing import Any

from app.models.schemas import RemediationTaskItem


class ServiceHelpersMixin:
    """Plan IDs, filenames, priorities, and type resolution helpers."""

    @staticmethod
    def _build_plan_id(*, review_id: str, finding: dict[str, Any]) -> str:
        finding_id = str(finding.get("finding_id") or "")
        finding_code = str(finding.get("finding_code") or "")
        return f"remediation:{review_id}:{finding_id or finding_code or 'finding'}"

    @staticmethod
    def _build_destination_folder(
        *, project_code: str, dossier_stage: str | None, document_type: str
    ) -> str:
        stage_segment = str(dossier_stage or "unspecified").strip() or "unspecified"
        return f"/projects/{project_code}/dossier/{stage_segment}/{document_type}"

    @staticmethod
    def _build_output_filename(
        *,
        project_code: str,
        document_type: str,
        dossier_stage: str | None,
        finding_code: str | None,
    ) -> str:
        stage_segment = str(dossier_stage or "unspecified").strip() or "unspecified"
        code_segment = str(finding_code or "finding").strip() or "finding"
        return f"{project_code}__{document_type}__{stage_segment}__{code_segment}.docx"

    def _task_item(
        self,
        *,
        plan_id: str,
        task_code: str,
        title: str,
        description: str,
        task_type: str,
        sequence_no: int,
        priority: str,
        owner_department_code: str | None,
        owner_employee_code: str | None,
        expected_output_codes: list[str],
        blocking: bool,
        dependency_task_codes: list[str] | None = None,
    ) -> RemediationTaskItem:
        """Tạo task item."""
        dependency_task_codes = dependency_task_codes or []
        dependency_task_ids = [
            self._task_id_from_code(plan_id=plan_id, task_code=code)
            for code in dependency_task_codes
        ]
        return RemediationTaskItem(
            task_id=f"{plan_id}:task:{sequence_no}",
            task_code=task_code,
            title=title,
            description=description,
            task_type=task_type,
            status="pending",
            priority=priority,
            sequence_no=sequence_no,
            owner_department_code=owner_department_code,
            owner_employee_code=owner_employee_code,
            dependency_task_ids=dependency_task_ids,
            expected_output_codes=expected_output_codes,
            blocking=blocking,
            metadata={"dependency_task_codes": dependency_task_codes},
        )

    @staticmethod
    def _task_id_from_code(*, plan_id: str, task_code: str) -> str:
        return f"{plan_id}:task-code:{task_code}"

    @staticmethod
    def _derive_priority(severity: Any, impact_level: Any, is_blocking: Any) -> str:
        normalized_severity = str(severity or "").strip().lower()
        normalized_impact = str(impact_level or "").strip().lower()
        if (
            bool(is_blocking)
            or normalized_severity in {"critical", "high"}
            or normalized_impact in {"critical", "high"}
        ):
            return "high"
        if normalized_severity in {"medium", "moderate"} or normalized_impact in {
            "medium",
            "moderate",
        }:
            return "medium"
        return "low"

    @staticmethod
    def _is_open_finding(value: Any) -> bool:
        normalized = str(value or "").strip().lower()
        return normalized not in {
            "",
            "resolved",
            "closed",
            "waived",
            "rejected",
            "accepted",
            "verified",
            "cancelled",
        }

    @staticmethod
    def _ensure_list(value: Any) -> list[dict[str, Any]]:
        if isinstance(value, list):
            return [item for item in value if isinstance(item, dict)]
        return []

    @staticmethod
    def _merge_messages(*messages: str | None) -> str | None:
        parts = [
            str(message).strip() for message in messages if str(message or "").strip()
        ]
        if not parts:
            return None
        return " | ".join(parts)

    @staticmethod
    def _string_int_dict(value: Any) -> dict[str, int]:
        if not isinstance(value, dict):
            return {}
        normalized: dict[str, int] = {}
        for key, raw in value.items():
            key_str = str(key).strip()
            if not key_str:
                continue
            try:
                normalized[key_str] = int(raw)
            except (TypeError, ValueError):
                normalized[key_str] = 0
        return normalized

    def _suggest_task_type(self, document_type: str | None) -> str | None:
        """Gợi ý task type tiếp theo."""
        normalized = str(document_type or "").strip()
        if not normalized:
            return None
        if "nghiem_thu" in normalized:
            return "payment_support"
        if "hop_dong" in normalized:
            return "contract_management"
        if "thanh_toan" in normalized or "khoi_luong" in normalized:
            return "payment_support"
        if "hoan_cong" in normalized or "quyet_toan" in normalized:
            return "closeout_documentation"
        return "dossier_inventory"

    def _derive_owner_codes(
        self, finding: dict[str, Any]
    ) -> tuple[str | None, str | None]:
        """Suy ra owner codes."""
        assignments = self._ensure_list(finding.get("assignments"))
        primary_assignment = assignments[0] if assignments else {}
        return (
            str(
                finding.get("responsible_department_code")
                or primary_assignment.get("assigned_department_code")
                or ""
            )
            or None,
            str(primary_assignment.get("assigned_employee_code") or "") or None,
        )
