"""Forecast hierarchy drift check."""

from __future__ import annotations

from typing import Any, Dict, List, Tuple

from .base import BaseScoutCheck, PreflightResult
from ..crm_provider import Filter, FilterExpr, FilterOp, OrGroup
from ..models import EvidenceRow, RecommendedAction


class ForecastHierarchyDriftCheck(BaseScoutCheck):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self._role_field = str(self.params.get("role_field") or "ForecastingRoleId")
        self._role_id = (self.params.get("role_id") or "").strip()

    def preflight(self) -> PreflightResult:
        base = super().preflight()
        if base.unsupported:
            return base
        try:
            desc = self.provider.describe("user")
            available = self._extract_field_names(desc)
            if self._role_field not in available:
                return PreflightResult(
                    ok=False,
                    unsupported=True,
                    reason=f"Field not found: {self._role_field}",
                )
        except Exception as exc:
            return PreflightResult(ok=False, unsupported=True, reason=str(exc))
        return base

    def build_count_filters(self) -> Tuple[str, List[FilterExpr]]:
        filters: List[FilterExpr] = []
        require_active = bool(self.params.get("require_active", True))
        if require_active:
            filters.append(Filter("IsActive", FilterOp.EQ, True))

        profile_ids = self.params.get("profile_ids") or []
        if profile_ids:
            filters.append(Filter("ProfileId", FilterOp.IN, profile_ids))

        if self._role_id:
            filters.append(
                OrGroup(
                    filters=[
                        Filter(self._role_field, FilterOp.IS_NULL),
                        Filter(self._role_field, FilterOp.NEQ, self._role_id),
                    ]
                )
            )
        else:
            filters.append(Filter(self._role_field, FilterOp.IS_NULL))

        return "user", filters

    def build_sample_request(self) -> Tuple[str, List[str], List[FilterExpr], str | None, str, bool]:
        fields = [
            "Id",
            "Name",
            "Email",
            "IsActive",
            "ProfileId",
            self._role_field,
        ]
        filters = self.build_count_filters()[1]
        return "user", fields, filters, "Name", "ASC", False

    def evaluate(self, rows: List[Dict[str, Any]]) -> List[EvidenceRow]:
        evidence: List[EvidenceRow] = []
        for row in rows:
            record_id = row.get("Id", "")
            if not record_id:
                continue
            role_value = row.get(self._role_field)
            reason_code = "MISSING_FORECAST_ROLE"
            reason = "Missing forecasting role"
            if self._role_id and role_value and role_value != self._role_id:
                reason_code = "FORECAST_ROLE_MISMATCH"
                reason = "Forecast role does not match expected role"
            fields = dict(row)
            if self._role_id:
                fields["expected_role_id"] = self._role_id
            evidence.append(
                EvidenceRow(
                    record_id=record_id,
                    sobject="user",
                    fields=fields,
                    reason=reason,
                    reason_code=reason_code,
                    severity=self.definition.severity_default,
                )
            )
        return evidence

    def get_recommended_actions(self) -> List[RecommendedAction]:
        if not self._role_id:
            return []
        return [
            RecommendedAction(
                action_type="sfdc.forecast.assign_user_to_role",
                label="Assign user to forecasting role",
                risk_level="low",
                details={"role_id": self._role_id},
            )
        ]

    def _extract_field_names(self, desc: Dict[str, Any]) -> set[str]:
        if "result" in desc:
            fields = desc.get("result", {}).get("fields", []) or []
            return {f.get("name") for f in fields if isinstance(f, dict) and f.get("name")}
        if "properties" in desc:
            props = desc.get("properties", []) or []
            return {p.get("name") for p in props if isinstance(p, dict) and p.get("name")}
        return set()


__all__ = ["ForecastHierarchyDriftCheck"]
