"""Deal Desk profile contracts for quote readiness and learned deal patterns."""

from __future__ import annotations

from typing import Any, Literal

from pydantic import BaseModel, ConfigDict, Field, computed_field


class _DealDeskProfileModel(BaseModel):
    model_config = ConfigDict(extra="ignore")

    def to_dict(self) -> dict[str, Any]:
        return self.model_dump(exclude_none=False, by_alias=True)

    @classmethod
    def from_dict(cls, data: dict[str, Any]) -> "_DealDeskProfileModel":
        return cls.model_validate(data)


class FieldMappingCandidate(_DealDeskProfileModel):
    semantic_key: str
    object_name: str
    field_name: str
    confidence: float = Field(default=0.0, ge=0.0, le=1.0)
    rationale: str = ""
    evidence_ids: list[str] = Field(default_factory=list)
    confirmed: bool = False


class PricebookSignal(_DealDeskProfileModel):
    pricebook_id: str | None = None
    pricebook_name: str
    usage_count: int = 0
    motion_labels: list[str] = Field(default_factory=list)
    active: bool = True


class TemplateSignal(_DealDeskProfileModel):
    template_key: str
    display_name: str
    usage_count: int = 0
    likely_for_motions: list[str] = Field(default_factory=list)
    confidence: float = Field(default=0.0, ge=0.0, le=1.0)


class ApprovalRouteSignal(_DealDeskProfileModel):
    route_key: str
    approver_roles: list[str] = Field(default_factory=list)
    trigger_summary: str = ""
    observed_count: int = 0
    confidence: float = Field(default=0.0, ge=0.0, le=1.0)


QuoteAdapterCapability = Literal[
    "read_status",
    "read_line_items",
    "simulate_or_price",
    "create_or_open_quote",
    "update_quote",
    "submit_for_approval",
    "generate_document",
    "read_signature_state",
    "publish_or_finalize",
]


class QuoteAdapterCapabilityProfileV1(_DealDeskProfileModel):
    version: int = 1
    adapter_key: str
    adapter_family: str
    detected_engine: str
    supported_capabilities: list[QuoteAdapterCapability] = Field(default_factory=list)
    execution_verified_capabilities: list[QuoteAdapterCapability] = Field(default_factory=list)
    unsupported_capabilities: list[QuoteAdapterCapability] = Field(default_factory=list)
    notes: list[str] = Field(default_factory=list)

    @computed_field
    @property
    def inferred_only_capabilities(self) -> list[QuoteAdapterCapability]:
        supported = set(self.supported_capabilities or [])
        execution_verified = set(self.execution_verified_capabilities or [])
        return sorted(capability for capability in supported if capability not in execution_verified)

    @computed_field
    @property
    def execution_verification_state(
        self,
    ) -> Literal["inferred_only", "partially_verified", "verified"]:
        supported = set(self.supported_capabilities or [])
        if not supported:
            return "inferred_only"
        execution_verified = {
            capability
            for capability in set(self.execution_verified_capabilities or [])
            if capability in supported
        }
        if not execution_verified:
            return "inferred_only"
        if execution_verified == supported:
            return "verified"
        return "partially_verified"

    @computed_field(alias="$schema")
    @property
    def schema(self) -> str:
        return "QuoteAdapterCapabilityProfile/v1"


class QuoteEnvironmentProfileV1(_DealDeskProfileModel):
    version: int = 1
    profile_id: str
    crm_org_id: str
    org_alias: str | None = None
    generated_at: str
    updated_at: str | None = None

    detected_engine: Literal["standard_quotes", "salesforce_cpq", "third_party", "mixed", "unknown"] = "unknown"
    engine_confidence: float = Field(default=0.0, ge=0.0, le=1.0)
    engine_evidence_ids: list[str] = Field(default_factory=list)

    quote_objects: list[str] = Field(default_factory=list)
    price_objects: list[str] = Field(default_factory=list)
    approval_objects: list[str] = Field(default_factory=list)
    template_objects: list[str] = Field(default_factory=list)

    calculator_endpoint: str | None = None
    pdf_generation_mode: Literal["native", "templated", "external", "unknown"] | None = None

    required_fields: dict[str, list[str]] = Field(default_factory=dict)
    field_mappings: list[FieldMappingCandidate] = Field(default_factory=list)
    pricebook_signals: list[PricebookSignal] = Field(default_factory=list)
    template_signals: list[TemplateSignal] = Field(default_factory=list)
    approval_route_signals: list[ApprovalRouteSignal] = Field(default_factory=list)
    adapter_capability_profile: QuoteAdapterCapabilityProfileV1 | None = None

    supported_capabilities: list[str] = Field(default_factory=list)
    unsupported_reasons: list[str] = Field(default_factory=list)
    evidence_ids: list[str] = Field(default_factory=list)
    source_receipt_ids: list[str] = Field(default_factory=list)

    @computed_field(alias="$schema")
    @property
    def schema(self) -> str:
        return "QuoteEnvironmentProfile/v1"


class DealMotionProfile(_DealDeskProfileModel):
    motion_id: str
    label: str
    confidence: float = Field(default=0.0, ge=0.0, le=1.0)
    heuristic_summary: str = ""
    observed_deal_count: int = 0
    common_products: list[str] = Field(default_factory=list)
    common_segments: list[str] = Field(default_factory=list)
    size_bands: list[str] = Field(default_factory=list)
    evidence_ids: list[str] = Field(default_factory=list)


class DealArchetype(_DealDeskProfileModel):
    archetype_id: str
    motion_id: str
    label: str
    segment: str | None = None
    product_family: str | None = None
    size_band: str | None = None
    typical_discount_pct: float | None = None
    p90_discount_pct: float | None = None
    typical_term_months: int | None = None
    typical_payment_terms: str | None = None
    common_templates: list[str] = Field(default_factory=list)
    common_approver_roles: list[str] = Field(default_factory=list)
    observed_deal_count: int = 0
    confidence: float = Field(default=0.0, ge=0.0, le=1.0)
    evidence_ids: list[str] = Field(default_factory=list)


class ApprovalPattern(_DealDeskProfileModel):
    pattern_id: str
    motion_id: str | None = None
    segment: str | None = None
    min_discount_pct: float | None = None
    max_discount_pct: float | None = None
    approver_roles: list[str] = Field(default_factory=list)
    median_approval_hours: float | None = None
    override_rate: float | None = None
    observed_count: int = 0
    confidence: float = Field(default=0.0, ge=0.0, le=1.0)
    evidence_ids: list[str] = Field(default_factory=list)


class StageBenchmark(_DealDeskProfileModel):
    stage_name: str
    motion_id: str | None = None
    median_hours_in_stage: float | None = None
    p90_hours_in_stage: float | None = None
    skip_rate: float | None = None
    stall_rate: float | None = None
    observed_count: int = 0


class PatternAnomalyRule(_DealDeskProfileModel):
    rule_id: str
    label: str
    description: str
    severity: Literal["low", "medium", "high", "critical"] = "medium"
    trigger_summary: str = ""


class DealPatternProfileV1(_DealDeskProfileModel):
    version: int = 1
    profile_id: str
    crm_org_id: str
    org_alias: str | None = None
    generated_at: str
    updated_at: str | None = None

    analysis_window_days: int = 365
    profile_confidence: float = Field(default=0.0, ge=0.0, le=1.0)
    learning_state: Literal["history_only", "history_plus_receipts", "mature"] = "history_only"

    motion_profiles: list[DealMotionProfile] = Field(default_factory=list)
    archetypes: list[DealArchetype] = Field(default_factory=list)
    approval_patterns: list[ApprovalPattern] = Field(default_factory=list)
    stage_benchmarks: list[StageBenchmark] = Field(default_factory=list)
    anomaly_rules: list[PatternAnomalyRule] = Field(default_factory=list)

    evidence_ids: list[str] = Field(default_factory=list)
    source_receipt_ids: list[str] = Field(default_factory=list)
    source_record_count: int = 0
    source_receipt_count: int = 0

    @computed_field(alias="$schema")
    @property
    def schema(self) -> str:
        return "DealPatternProfile/v1"


class PatternExtractedSignals(_DealDeskProfileModel):
    discount_pct: float | None = None
    term_months: int | None = None
    payment_terms: str | None = None
    template_key: str | None = None
    approver_roles: list[str] = Field(default_factory=list)
    approval_latency_hours: float | None = None
    stage_durations: dict[str, float] = Field(default_factory=dict)
    exception_flags: list[str] = Field(default_factory=list)
    bundle_signature: str | None = None
    outcome: str | None = None
    custom: dict[str, Any] = Field(default_factory=dict)


class PatternUpdateEventV1(_DealDeskProfileModel):
    version: int = 1
    event_id: str
    crm_org_id: str
    opportunity_id: str | None = None
    observed_at: str

    source_type: Literal[
        "historical_deal",
        "quote_receipt",
        "line_items_receipt",
        "rollback_receipt",
        "approval_receipt",
        "close_packet",
        "close_submission",
        "close_progression",
        "reconciliation_packet",
        "approval_stamp",
        "renewal_shell",
        "post_close_trigger",
    ]
    source_ref: str
    source_receipt_id: str | None = None

    extracted_motion_id: str | None = None
    extracted_signals: PatternExtractedSignals = Field(default_factory=PatternExtractedSignals)
    confidence: float = Field(default=0.0, ge=0.0, le=1.0)
    evidence_ids: list[str] = Field(default_factory=list)

    @computed_field(alias="$schema")
    @property
    def schema(self) -> str:
        return "PatternUpdateEvent/v1"


__all__ = [
    "FieldMappingCandidate",
    "PricebookSignal",
    "TemplateSignal",
    "ApprovalRouteSignal",
    "QuoteAdapterCapability",
    "QuoteAdapterCapabilityProfileV1",
    "QuoteEnvironmentProfileV1",
    "DealMotionProfile",
    "DealArchetype",
    "ApprovalPattern",
    "StageBenchmark",
    "PatternAnomalyRule",
    "DealPatternProfileV1",
    "PatternExtractedSignals",
    "PatternUpdateEventV1",
]
