"""Append candidates check (missing required fields)."""

from __future__ import annotations

from typing import Any, Dict, List

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


CONTACT_REASON_CODES = {
    "Email": "MISSING_EMAIL",
    "Phone": "MISSING_PHONE",
}

ACCOUNT_REASON_CODES = {
    "Website": "MISSING_WEBSITE",
    "Industry": "MISSING_INDUSTRY",
    "NumberOfEmployees": "MISSING_FIRMOGRAPHICS",
}


class AppendCandidatesCheck(BaseScoutCheck):
    def build_count_filters(self) -> tuple[str, List[FilterExpr]]:
        return "account", []

    def build_sample_request(self) -> tuple[str, List[str], List[FilterExpr], str | None, str, bool]:
        return "account", ["Id"], [], None, "ASC", False

    def evaluate(self, rows: List[Dict[str, Any]]) -> List[EvidenceRow]:
        return []

    def execute(self) -> ScoutFinding:
        # Custom execution to support multiple sobjects
        import time

        started = time.perf_counter()
        evidence: List[EvidenceRow] = []
        total_scanned = 0

        check_contacts = bool(self.params.get("check_contacts", True))
        check_accounts = bool(self.params.get("check_accounts", True))
        contact_fields = self.params.get("required_contact_fields", ["Email", "Phone"]) or []
        account_fields = self.params.get("required_account_fields", ["Website", "Industry", "NumberOfEmployees"]) or []

        if check_contacts:
            if not self.provider.supports_object("contact"):
                self._warnings.append("Contact object unsupported; skipping contact checks.")
            else:
                contact_filters = self._missing_field_filters(contact_fields)
                count = self.provider.count("contact", contact_filters)
                self._collect_provider_meta()
                total_scanned += count
                rows = self.provider.query(
                    "contact",
                    self._select_fields(contact_fields),
                    contact_filters,
                    order_by="CreatedDate",
                    order_dir="DESC",
                    limit=self.top_n,
                )
                self._collect_provider_meta()
                evidence.extend(self._evaluate_rows(rows, "contact", contact_fields))

        if check_accounts:
            if not self.provider.supports_object("account"):
                self._warnings.append("Account object unsupported; skipping account checks.")
            else:
                account_filters = self._missing_field_filters(account_fields)
                count = self.provider.count("account", account_filters)
                self._collect_provider_meta()
                total_scanned += count
                rows = self.provider.query(
                    "account",
                    self._select_fields(account_fields),
                    account_filters,
                    order_by="CreatedDate",
                    order_dir="DESC",
                    limit=self.top_n,
                )
                self._collect_provider_meta()
                evidence.extend(self._evaluate_rows(rows, "account", account_fields))

        total_findings = len(evidence)
        if len(evidence) > self.top_n:
            evidence = evidence[: self.top_n]

        if total_scanned == 0 and not evidence:
            status = "ok"
        else:
            status = "findings" if total_scanned > 0 else "ok"
        duration_ms = int((time.perf_counter() - started) * 1000)
        return ScoutFinding(
            scout_name=self.definition.name,
            display_name=self.definition.display_name,
            description=self.definition.description,
            category=self.definition.category,
            severity=self.definition.severity_default,
            total_records_scanned=total_scanned,
            findings_count=total_findings,
            evidence=evidence,
            recommended_actions=self.get_recommended_actions(),
            soql_queries=self._soql_queries,
            duration_ms=duration_ms,
            parameters_used=self.params,
            status=status,
            warnings=self._warnings,
        )

    def _missing_field_filters(self, fields: List[str]) -> List[FilterExpr]:
        if not fields:
            return []
        clauses = [Filter(str(field), FilterOp.IS_NULL) for field in fields]
        return [OrGroup(filters=clauses)]

    def _select_fields(self, fields: List[str]) -> List[str]:
        base_fields = ["Id", "Name"]
        return base_fields + [f for f in fields if f not in base_fields]

    def _evaluate_rows(self, rows: List[Dict[str, Any]], sobject: str, fields: List[str]) -> List[EvidenceRow]:
        evidence: List[EvidenceRow] = []
        reason_map = CONTACT_REASON_CODES if sobject == "contact" else ACCOUNT_REASON_CODES

        for row in rows:
            record_id = row.get("Id", "")
            if not record_id:
                continue
            for field in fields:
                value = row.get(field)
                if value is None or value == "":
                    reason_code = reason_map.get(field, "MISSING_FIELD")
                    reason = f"Missing {field}"
                    evidence.append(
                        EvidenceRow(
                            record_id=record_id,
                            sobject=sobject,
                            fields={
                                "Name": row.get("Name"),
                                field: value,
                            },
                            reason=reason,
                            reason_code=reason_code,
                            severity=self.definition.severity_default,
                        )
                    )
        return evidence

    def get_recommended_actions(self) -> List[RecommendedAction]:
        return [
            RecommendedAction(
                action_type="export_csv",
                label="Export append candidates to CSV",
                risk_level="safe",
            ),
            RecommendedAction(
                action_type="enrich_missing_fields",
                label="Auto-enrich missing fields",
                risk_level="low",
                details={
                    "providers": ["zoominfo", "apollo", "clearbit"],
                    "confidence_floor": 0.7,
                    "only_fill_empty_fields": True,
                    "max_provider_calls_per_run": 100,
                },
            ),
        ]


__all__ = ["AppendCandidatesCheck"]
