"""Data models for symbol resolution results."""

from __future__ import annotations

from enum import Enum

from pydantic import BaseModel, Field


class MatchType(str, Enum):
    """How a resolution candidate was matched."""

    exact_ticker = "exact_ticker"
    exact_name = "exact_name"
    alias = "alias"
    fuzzy = "fuzzy"


class MentionType(str, Enum):
    """Whether a mention is explicitly stated or inferred from context."""

    explicit = "explicit"
    inferred = "inferred"


class UnresolvedReason(str, Enum):
    """Why a mention could not be resolved."""

    not_in_registry = "not_in_registry"
    ambiguous = "ambiguous"
    context_needed = "context_needed"


class ResolutionCandidate(BaseModel):
    """A single candidate match from the symbol registry.

    Candidates are ranked by confidence, with match_type indicating how
    the match was derived.
    """

    company_id: str = Field(description="UUID of the matched company")
    ticker: str = Field(description="Ticker symbol of the matched company")
    name: str = Field(description="Legal or display name of the matched company")
    confidence: float = Field(ge=0.0, le=1.0, description="Match confidence score")
    match_type: MatchType = Field(description="How the match was derived")


class ResolutionResult(BaseModel):
    """Full resolution output for a single mention.

    Contains ranked candidates, ambiguity margin, and mention classification.
    """

    candidates: list[ResolutionCandidate] = Field(default_factory=list)
    ambiguity_margin: float = Field(
        default=1.0,
        ge=0.0,
        le=1.0,
        description="Difference between top-2 candidate confidences. 1.0 = unambiguous single match, 0.0 = tied.",
    )
    is_ambiguous: bool = Field(
        default=False,
        description="True when top candidates are too close to distinguish without context.",
    )
    mention_type: MentionType = Field(
        default=MentionType.explicit,
        description="Whether the mention is explicit text or inferred exposure.",
    )


class UnresolvedMention(BaseModel):
    """A mention that could not be resolved to any company in the registry.

    Preserved as-is rather than having a ticker invented for it.
    """

    literal_text: str = Field(description="Original text as it appeared in the document")
    start_char: int = Field(ge=0, description="Start character offset in source document")
    end_char: int = Field(gt=0, description="End character offset (exclusive)")
    reason: UnresolvedReason = Field(description="Why resolution failed")
