"""Forecast hygiene check."""

from __future__ import annotations

from typing import Any, Dict, List, Tuple

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


class ForecastHygieneCheck(BaseScoutCheck):
    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self._forecast_field: str | None = "ForecastCategory"

    def preflight(self) -> PreflightResult:
        base = super().preflight()
        if base.unsupported:
            return base
        try:
            desc = self.provider.describe("opportunity")
            available = self._extract_field_names(desc)
            if "ForecastCategory" in available:
                self._forecast_field = "ForecastCategory"
            elif "ForecastCategoryName" in available:
                self._forecast_field = "ForecastCategoryName"
            else:
                self._forecast_field = None
                self._warnings.append("ForecastCategory not found; skipping forecast category check.")
        except Exception:
            self._forecast_field = None
        return base

    def build_count_filters(self) -> Tuple[str, List[FilterExpr]]:
        filters: List[FilterExpr] = [Filter("IsClosed", FilterOp.EQ, False)]
        exclude = self.params.get("exclude_stages", []) or []
        if exclude:
            filters.append(Filter("StageName", FilterOp.NOT_IN, exclude))
        if self.params.get("min_amount", 0):
            filters.append(Filter("Amount", FilterOp.GTE, self.params["min_amount"]))
        return "opportunity", filters

    def build_sample_request(self) -> Tuple[str, List[str], List[FilterExpr], str | None, str, bool]:
        fields = [
            "Id",
            "Name",
            "Amount",
            "StageName",
            "CloseDate",
            "OwnerId",
            "CreatedDate",
            "Probability",
        ]
        if self._forecast_field:
            fields.append(self._forecast_field)
        filters = self.build_count_filters()[1]
        return "opportunity", fields, filters, "CloseDate", "ASC", False

    def evaluate(self, rows: List[Dict[str, Any]]) -> List[EvidenceRow]:
        evidence: List[EvidenceRow] = []
        check_amount = bool(self.params.get("check_amount", True))
        check_close = bool(self.params.get("check_close_date", True))
        check_forecast = bool(self.params.get("check_forecast_category", True)) and bool(self._forecast_field)
        max_past_days = int(self.params.get("max_past_days", 0))

        for row in rows:
            record_id = row.get("Id", "")
            if not record_id:
                continue
            base_fields = {k: row.get(k) for k in row}

            if check_close:
                days_past = days_since(row.get("CloseDate"))
                if days_past is not None and days_past > max_past_days:
                    evidence.append(
                        EvidenceRow(
                            record_id=record_id,
                            sobject="opportunity",
                            fields={**base_fields, "days_past_close": days_past},
                            reason=f"CloseDate {days_past} days in the past",
                            reason_code="CLOSE_DATE_PAST",
                            severity=self.definition.severity_default,
                        )
                    )

            if check_amount:
                amount = row.get("Amount")
                if amount is None:
                    missing_amount = True
                elif isinstance(amount, (int, float)):
                    missing_amount = amount == 0
                else:
                    text = str(amount).strip()
                    missing_amount = text == "" or text == "0" or text == "0.0"
                if missing_amount:
                    evidence.append(
                        EvidenceRow(
                            record_id=record_id,
                            sobject="opportunity",
                            fields=dict(base_fields),
                            reason="Amount is zero or missing",
                            reason_code="MISSING_AMOUNT",
                            severity=self.definition.severity_default,
                        )
                    )

            if check_forecast and self._forecast_field:
                fc = row.get(self._forecast_field) or row.get("ForecastCategoryName")
                if not fc:
                    evidence.append(
                        EvidenceRow(
                            record_id=record_id,
                            sobject="opportunity",
                            fields=dict(base_fields),
                            reason="Missing forecast category",
                            reason_code="MISSING_FORECAST_CATEGORY",
                            severity="medium",
                        )
                    )

        return evidence

    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()

    def get_recommended_actions(self) -> List[RecommendedAction]:
        return [
            RecommendedAction(
                action_type="export_csv",
                label="Export forecast hygiene issues",
                risk_level="safe",
            ),
            RecommendedAction(
                action_type="create_task",
                label="Create tasks for forecast hygiene",
                risk_level="low",
            ),
            RecommendedAction(
                action_type="flag_record",
                label="Flag forecast hygiene issues",
                risk_level="low",
            ),
        ]


__all__ = ["ForecastHygieneCheck"]
