"""
Forecast pre-recon service.

Inspects Salesforce metadata and a small opportunity sample to propose sensible
defaults for the Forecast Operating Sheet interview.
"""

from __future__ import annotations

import logging
from typing import Any, Dict, List, Optional

from .salesforce_gateway import SalesforceGateway

logger = logging.getLogger(__name__)


class ForecastReconService:
    """Perform lightweight metadata inspection for the Forecast template."""

    def __init__(self, gateway: SalesforceGateway):
        self.gateway = gateway

    async def run_recon(self, integration_id: str) -> Dict[str, Any]:
        """
        Run metadata inspection and return recommendations.

        The integration_id is accepted for traceability even though the gateway
        is already scoped to the tenant.
        """
        logger.info("[FORECAST] Starting recon for integration=%s", integration_id)

        opp_describe = await self._safe_describe("Opportunity")
        opp_fields = opp_describe.get("fields", []) if isinstance(opp_describe, dict) else []

        record_types = await self._safe_query(
            "SELECT Id, Name, DeveloperName FROM RecordType "
            "WHERE SObjectType = 'Opportunity' AND IsActive = true"
        )
        record_type_rows = record_types.get("records", []) if isinstance(record_types, dict) else []

        fc_field = self._find_field(opp_fields, ["ForecastCategoryName", "ForecastCategory", "Forecast_Category__c"])
        forecast_categories = self._extract_picklist(fc_field)

        sample_query = (
            "SELECT Id, Amount, AnnualContractValue__c, ARR__c, RecordType.Name, Type, "
            "ForecastCategoryName, OwnerId, Owner.Name, CloseDate, StageName, Probability, "
            "IsWon, IsClosed, CreatedDate, LastModifiedDate "
            "FROM Opportunity WHERE CloseDate >= LAST_N_DAYS:90 LIMIT 100"
        )
        sample = await self._safe_query(sample_query)
        sample_rows = sample.get("records", []) if isinstance(sample, dict) else []

        custom_fields = self._detect_custom_fields(
            opp_fields,
            [
                "ARR__c",
                "ACV__c",
                "Annual_Contract_Value__c",
                "Booking_Amount__c",
                "Is_Renewal__c",
                "Renewal__c",
                "Deal_Type__c",
                "Credit_Rep__c",
                "Sales_Rep__c",
                "Account_Owner__c",
            ],
        )

        revenue_rec = self._detect_revenue_field(opp_fields, sample_rows)
        renewal_rec = self._detect_renewal_logic(record_type_rows, opp_fields, sample_rows)
        credit_rec = self._detect_credit_owner_field(opp_fields, custom_fields)

        recommendations = {
            "revenue_field": revenue_rec,
            "renewal_rule": renewal_rec,
            "credit_owner_field": credit_rec,
            "forecast_category_source": {
                "field": (fc_field or {}).get("name", "ForecastCategoryName"),
                "confidence": 0.85 if fc_field else 0.4,
            },
            "excluded_stages": ["Closed Lost"],
            "included_record_types": [],
            "close_date_window_days": 365,
        }

        confidence_scores = {
            "revenue": revenue_rec.get("confidence", 0.0),
            "renewal": renewal_rec.get("confidence", 0.0),
            "credit_owner": credit_rec.get("confidence", 0.0),
            "category_field": 0.85 if fc_field else 0.4,
        }

        sample_preview = self._summarize_sample(sample_rows)

        return {
            "status": "completed",
            "recommendations": recommendations,
            "confidence_scores": confidence_scores,
            "sample_preview": sample_preview,
            "detected_fields": opp_fields,
            "record_types": record_type_rows,
            "forecast_categories": forecast_categories,
            "custom_fields": custom_fields,
        }

    # ------------------------------------------------------------------ #
    # Detection helpers
    # ------------------------------------------------------------------ #
    def _find_field(self, fields: List[Dict[str, Any]], candidates: List[str]) -> Optional[Dict[str, Any]]:
        names = {f.get("name"): f for f in fields if isinstance(f, dict)}
        for name in candidates:
            if name in names:
                return names[name]
        # Attempt case-insensitive match
        lower = {str(k).lower(): v for k, v in names.items()}
        for name in candidates:
            match = lower.get(name.lower())
            if match:
                return match
        return None

    def _extract_picklist(self, field: Optional[Dict[str, Any]]) -> List[str]:
        if not field:
            return []
        values = field.get("picklistValues") or []
        return [v.get("label") or v.get("value") for v in values if isinstance(v, dict)]

    def _detect_custom_fields(self, fields: List[Dict[str, Any]], names: List[str]) -> List[str]:
        found = []
        available = {f.get("name", "") for f in fields if isinstance(f, dict)}
        for name in names:
            if name in available:
                found.append(name)
        return found

    def _detect_revenue_field(self, fields: List[Dict[str, Any]], sample: List[Dict[str, Any]]) -> Dict[str, Any]:
        field = self._find_field(fields, ["Amount", "ARR__c", "ACV__c", "AnnualContractValue__c", "Annual_Contract_Value__c"])
        best_field = (field or {}).get("name", "Amount")
        coverage = self._field_coverage(sample, best_field)
        confidence = 0.9 if best_field == "Amount" and coverage >= 0.5 else 0.65 if coverage >= 0.3 else 0.4
        return {"field": best_field, "confidence": confidence, "coverage": coverage}

    def _detect_renewal_logic(
        self,
        record_types: List[Dict[str, Any]],
        fields: List[Dict[str, Any]],
        sample: List[Dict[str, Any]],
    ) -> Dict[str, Any]:
        rt_names = [str(rt.get("Name", "")).lower() for rt in record_types]
        type_field = self._find_field(fields, ["Type"])
        renewal_by_rt = any("renewal" in name for name in rt_names)
        renewal_by_type = False
        if type_field:
            renewal_by_type = any(str(row.get("Type", "")).lower() == "renewal" for row in sample)

        if renewal_by_rt:
            return {"method": "record_type", "value": "Renewal", "confidence": 0.85}
        if renewal_by_type:
            return {"method": "type_picklist", "value": "Renewal", "confidence": 0.7}

        checkbox = self._find_field(fields, ["Is_Renewal__c", "Renewal__c"])
        if checkbox:
            return {"method": "checkbox", "value": checkbox.get("name"), "confidence": 0.6}

        return {"method": "record_type", "value": None, "confidence": 0.3}

    def _detect_credit_owner_field(self, fields: List[Dict[str, Any]], custom_fields: List[str]) -> Dict[str, Any]:
        custom_candidates = [f for f in custom_fields if "owner" in f.lower() or "rep" in f.lower()]
        if custom_candidates:
            return {"field": custom_candidates[0], "confidence": 0.7}
        # Default to OwnerId
        owner_field = self._find_field(fields, ["OwnerId"])
        return {"field": (owner_field or {}).get("name", "OwnerId"), "confidence": 0.85}

    def _field_coverage(self, sample: List[Dict[str, Any]], field_name: str) -> float:
        if not sample or not field_name:
            return 0.0
        populated = sum(1 for row in sample if row.get(field_name) not in (None, "", 0))
        return round(populated / len(sample), 3)

    def _summarize_sample(self, sample: List[Dict[str, Any]]) -> Dict[str, Any]:
        total = len(sample)
        won = sum(1 for row in sample if row.get("IsWon"))
        closed = sum(1 for row in sample if row.get("IsClosed"))
        renewal_guess = sum(1 for row in sample if str(row.get("Type", "")).lower() == "renewal")
        return {
            "total": total,
            "won": won,
            "closed": closed,
            "renewal_candidates": renewal_guess,
        }

    # ------------------------------------------------------------------ #
    # Gateway helpers
    # ------------------------------------------------------------------ #
    async def _safe_describe(self, sobject: str) -> Dict[str, Any]:
        try:
            return await self.gateway.describe_object(sobject)
        except Exception as exc:  # pragma: no cover - defensive
            logger.warning("Describe %s failed: %s", sobject, exc)
            return {}

    async def _safe_query(self, query: str) -> Dict[str, Any]:
        try:
            return await self.gateway.soql(query)
        except Exception as exc:  # pragma: no cover - defensive
            logger.warning("SOQL query failed: %s", exc)
            return {}
