"""Account hierarchy hygiene check (Salesforce only)."""

from __future__ import annotations

import time
from typing import Any, Dict, List, Tuple

from .base import BaseScoutCheck, PreflightResult
from ..crm_provider import Filter, FilterExpr, FilterOp
from ..domain_utils import extract_registrable_domain
from ..models import EvidenceRow, RecommendedAction, ScoutFinding


class AccountHierarchyCheck(BaseScoutCheck):
    def preflight(self) -> PreflightResult:
        base = super().preflight()
        if base.unsupported:
            return base
        try:
            desc = self.provider.describe("account")
            fields = self._extract_field_names(desc)
            if "ParentId" not in fields and "parentid" not in {f.lower() for f in fields}:
                return PreflightResult(
                    ok=False,
                    unsupported=True,
                    reason="ParentId not available on Account.",
                )
        except Exception:
            pass
        return base

    def build_count_filters(self) -> Tuple[str, List[FilterExpr]]:
        return "account", [Filter("Website", FilterOp.IS_NOT_NULL)]

    def build_sample_request(self) -> Tuple[str, List[str], List[FilterExpr], str | None, str, bool]:
        fields = ["Id", "Name", "Website", "ParentId", "OwnerId", "LastActivityDate", "CreatedDate"]
        filters = self.build_count_filters()[1]
        return "account", fields, filters, "Website", "ASC", False

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

    def execute(self) -> ScoutFinding:  # type: ignore[override]
        start = time.perf_counter()
        evidence: List[EvidenceRow] = []
        total_scanned = 0

        check_duplicate_roots = bool(self.params.get("check_duplicate_roots", True))
        check_orphaned_parents = bool(self.params.get("check_orphaned_parents", False))
        min_domain_accounts = int(self.params.get("min_domain_accounts", 2))

        filters = self.build_count_filters()[1]
        total_scanned = self.provider.count("account", filters)
        self._collect_provider_meta()

        rows = self.provider.query(
            "account",
            ["Id", "Name", "Website", "ParentId", "OwnerId", "LastActivityDate", "CreatedDate"],
            filters,
            order_by="Website",
            order_dir="ASC",
            limit=self.top_n,
        )
        self._collect_provider_meta()

        domain_groups: Dict[str, List[Dict[str, Any]]] = {}
        parent_ids: set[str] = set()
        rows_by_id: Dict[str, Dict[str, Any]] = {}

        for row in rows:
            record_id = row.get("Id")
            if record_id:
                rows_by_id[str(record_id)] = row
            parent_id = row.get("ParentId")
            if parent_id:
                parent_ids.add(str(parent_id))
            domain = extract_registrable_domain(row.get("Website"))
            if not domain:
                continue
            domain_groups.setdefault(domain, []).append(row)

        if check_duplicate_roots:
            for domain, group in domain_groups.items():
                roots = [r for r in group if not r.get("ParentId")]
                if len(roots) >= min_domain_accounts:
                    for row in roots:
                        record_id = row.get("Id", "")
                        if not record_id:
                            continue
                        evidence.append(
                            EvidenceRow(
                                record_id=record_id,
                                sobject="account",
                                fields={
                                    "Name": row.get("Name"),
                                    "Website": row.get("Website"),
                                    "domain": domain,
                                    "ParentId": row.get("ParentId"),
                                    "OwnerId": row.get("OwnerId"),
                                    "root_count_for_domain": len(roots),
                                },
                                reason=f"Domain {domain} has {len(roots)} unlinked parent accounts",
                                reason_code="DUPLICATE_ROOT",
                                severity=self.definition.severity_default,
                            )
                        )

        if check_orphaned_parents:
            for parent_id in parent_ids:
                row = rows_by_id.get(parent_id)
                if not row:
                    continue
                if row.get("OwnerId") and row.get("LastActivityDate"):
                    continue
                evidence.append(
                    EvidenceRow(
                        record_id=parent_id,
                        sobject="account",
                        fields={
                            "Name": row.get("Name"),
                            "Website": row.get("Website"),
                            "ParentId": row.get("ParentId"),
                            "OwnerId": row.get("OwnerId"),
                            "LastActivityDate": row.get("LastActivityDate"),
                        },
                        reason="Parent account with no owner or activity",
                        reason_code="ORPHANED_PARENT",
                        severity=self.definition.severity_default,
                    )
                )

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

        status = "findings" if total_findings > 0 else "ok"
        duration_ms = int((time.perf_counter() - start) * 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 _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 account hierarchy issues",
                risk_level="safe",
            ),
            RecommendedAction(
                action_type="create_task",
                label="Create tasks for hierarchy issues",
                risk_level="low",
            ),
            RecommendedAction(
                action_type="flag_record",
                label="Flag hierarchy issues",
                risk_level="low",
            ),
        ]


__all__ = ["AccountHierarchyCheck"]
