"""Aging / stalled opportunities check."""

from __future__ import annotations

from typing import Dict, List, Tuple

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


class AgingOppsCheck(BaseScoutCheck):
    """Find open opportunities with inactivity or missing next steps."""

    def __init__(self, *args, **kwargs) -> None:
        super().__init__(*args, **kwargs)
        self._has_stage_change_date = True

    def preflight(self) -> PreflightResult:
        base = super().preflight()
        if base.unsupported:
            return base
        if self.provider.name != "salesforce":
            self._has_stage_change_date = False
            return base
        try:
            desc = self.provider.describe("opportunity")
            fields = desc.get("result", {}).get("fields", []) or []
            names = {f.get("name") for f in fields if isinstance(f, dict)}
            if "LastStageChangeDate" not in names:
                self._has_stage_change_date = False
                self._warnings.append(
                    "LastStageChangeDate not accessible; using CreatedDate for stage age."
                )
        except Exception:
            pass
        return base

    def build_count_filters(self) -> Tuple[str, List[FilterExpr]]:
        inactive_days = int(self.params.get("inactive_days", 14))
        stage_age_days = int(self.params.get("stage_age_days", 30))
        require_next_step = bool(self.params.get("require_next_step", True))
        exclude_stages = self.params.get("exclude_stages", []) or []
        min_amount = self.params.get("min_amount", 0)
        stage_field = "LastStageChangeDate" if self._has_stage_change_date else "CreatedDate"

        filters: List[FilterExpr] = [Filter("IsClosed", FilterOp.EQ, False)]
        if exclude_stages:
            filters.append(Filter("StageName", FilterOp.NOT_IN, exclude_stages))
        if min_amount:
            filters.append(Filter("Amount", FilterOp.GTE, min_amount))

        reasons = [
            Filter("LastActivityDate", FilterOp.IS_NULL),
            Filter("LastActivityDate", FilterOp.NOT_LAST_N_DAYS, inactive_days),
            Filter(stage_field, FilterOp.IS_NULL),
            Filter(stage_field, FilterOp.NOT_LAST_N_DAYS, stage_age_days),
        ]
        if require_next_step:
            reasons.append(Filter("NextStep", FilterOp.IS_NULL))
            reasons.append(Filter("NextStep", FilterOp.EQ, ""))

        filters.append(OrGroup(filters=reasons))
        return "opportunity", filters

    def build_sample_request(self) -> Tuple[str, List[str], List[FilterExpr], str | None, str, bool]:
        inactive_days = int(self.params.get("inactive_days", 14))
        stage_age_days = int(self.params.get("stage_age_days", 30))
        require_next_step = bool(self.params.get("require_next_step", True))
        exclude_stages = self.params.get("exclude_stages", []) or []
        min_amount = self.params.get("min_amount", 0)
        stage_field = "LastStageChangeDate" if self._has_stage_change_date else "CreatedDate"

        filters: List[FilterExpr] = [Filter("IsClosed", FilterOp.EQ, False)]
        if exclude_stages:
            filters.append(Filter("StageName", FilterOp.NOT_IN, exclude_stages))
        if min_amount:
            filters.append(Filter("Amount", FilterOp.GTE, min_amount))

        reasons = [
            Filter("LastActivityDate", FilterOp.IS_NULL),
            Filter("LastActivityDate", FilterOp.NOT_LAST_N_DAYS, inactive_days),
            Filter(stage_field, FilterOp.IS_NULL),
            Filter(stage_field, FilterOp.NOT_LAST_N_DAYS, stage_age_days),
        ]
        if require_next_step:
            reasons.append(Filter("NextStep", FilterOp.IS_NULL))
            reasons.append(Filter("NextStep", FilterOp.EQ, ""))

        filters.append(OrGroup(filters=reasons))
        fields = [
            "Id",
            "Name",
            "Amount",
            "StageName",
            "LastActivityDate",
            stage_field,
            "NextStep",
            "OwnerId",
            "CloseDate",
            "CreatedDate",
        ]
        return (
            "opportunity",
            list(dict.fromkeys(fields)),
            filters,
            "LastActivityDate",
            "ASC",
            True,
        )

    def evaluate(self, rows: List[Dict[str, str]]) -> List[EvidenceRow]:
        evidence: List[EvidenceRow] = []
        inactive_days = int(self.params.get("inactive_days", 14))
        stage_age_days = int(self.params.get("stage_age_days", 30))
        require_next_step = bool(self.params.get("require_next_step", True))

        for row in rows:
            record_id = row.get("Id", "")
            if not record_id:
                continue
            fields = {
                "Name": row.get("Name"),
                "StageName": row.get("StageName"),
                "Amount": row.get("Amount"),
                "LastActivityDate": row.get("LastActivityDate"),
                "LastStageChangeDate": row.get("LastStageChangeDate"),
                "NextStep": row.get("NextStep"),
                "OwnerId": row.get("OwnerId"),
                "CloseDate": row.get("CloseDate"),
            }

            days_since_activity = days_since(row.get("LastActivityDate"))
            if days_since_activity is None or days_since_activity >= inactive_days:
                fields["days_since_activity"] = days_since_activity
                evidence.append(
                    EvidenceRow(
                        record_id=record_id,
                        sobject="opportunity",
                        fields=dict(fields),
                        reason=f"No activity in {days_since_activity or 'unknown'} days",
                        reason_code="NO_ACTIVITY",
                        severity=self.definition.severity_default,
                    )
                )

            days_in_stage = days_since(row.get("LastStageChangeDate"))
            if days_in_stage is None:
                days_in_stage = days_since(row.get("CreatedDate"))
            if days_in_stage is not None and days_in_stage >= stage_age_days:
                fields["days_in_stage"] = days_in_stage
                evidence.append(
                    EvidenceRow(
                        record_id=record_id,
                        sobject="opportunity",
                        fields=dict(fields),
                        reason=f"Stage age {days_in_stage} days",
                        reason_code="STAGE_AGE",
                        severity=self.definition.severity_default,
                    )
                )

            if require_next_step:
                next_step = row.get("NextStep")
                if not next_step:
                    evidence.append(
                        EvidenceRow(
                            record_id=record_id,
                            sobject="opportunity",
                            fields=dict(fields),
                            reason="Missing next step",
                            reason_code="MISSING_NEXT_STEP",
                            severity=self.definition.severity_default,
                        )
                    )

        return evidence

    def get_recommended_actions(self) -> List[RecommendedAction]:
        return [
            RecommendedAction(
                action_type="create_task",
                label="Create follow-up tasks for stale opportunities",
                risk_level="low",
            ),
            RecommendedAction(
                action_type="flag_record",
                label="Flag opportunities for review",
                risk_level="low",
            ),
            RecommendedAction(
                action_type="export_csv",
                label="Export stale opportunities to CSV",
                risk_level="safe",
            ),
        ]


__all__ = ["AgingOppsCheck"]
