"""Configuration models for the fuzzy matching engine.

Provides Pydantic models for tenant-specific matching configuration.
All matching behavior (thresholds, synonyms, stopwords, field mappings)
is controlled through these configuration objects.

Usage::

    from entr_adapter_core.utils.matching import MatchConfig

    config = MatchConfig(
        id_field="ItemCode",
        description_field="Description",
        score_threshold=90.0,
        synonym_map={"bubble": "bubbel", "stretch": "wikkelfolie"},
        stopwords={"de", "het", "een"},
    )
"""

from __future__ import annotations

from typing import Dict, List, Optional, Set

from pydantic import BaseModel, Field


class MatchConfig(BaseModel):
    """Configuration for the fuzzy matching engine.

    Controls which fields to match on, scoring thresholds, text
    normalization (synonyms/stopwords), and scorer weights.

    Attributes:
        id_field: Name of the unique identifier field in entity dicts.
        description_field: Name of the primary text field to match against.
        search_fields: Additional fields to search when collecting candidates.
            Combined with ``description_field`` for token matching.
        score_threshold: Minimum score for a match to be considered
            "high confidence". Scores above this are auto-accepted in
            many adapter workflows.
        high_confidence_threshold: Score at or above which a match is
            considered "very high confidence".
        low_confidence_threshold: Score below which a match is flagged
            as "low confidence" and may need manual review.
        min_tokens_to_match: Minimum number of query tokens required
            before the engine attempts matching.
        synonym_map: Maps variant spellings to canonical forms.
            Applied during text normalization before scoring.
        stopwords: Tokens to remove during normalization. Typically
            filler words and units that are not distinctive.
        scorer_weights: Weights for the four rapidfuzz scorers.
            Keys: ``wratio``, ``token_sort``, ``token_set``, ``partial``.
            Must sum to ~1.0. Defaults to empirically tuned values.
        max_tokens: Maximum query tokens to use. Longer queries are
            trimmed to the most specific (longest) tokens.
        max_combinations_per_level: Cap on token combinations per
            candidate-generation level. Prevents combinatorial explosion
            on long queries.
    """

    id_field: str = Field(
        default="id",
        description="Name of the unique identifier field in entity dicts",
    )
    description_field: str = Field(
        default="description",
        description="Name of the primary text field to match against",
    )
    search_fields: List[str] = Field(
        default_factory=list,
        description="Additional fields to include in token-based candidate search",
    )
    score_threshold: float = Field(
        default=90.0,
        ge=0.0,
        le=100.0,
        description="Minimum score for 'high confidence' match",
    )
    high_confidence_threshold: float = Field(
        default=95.0,
        ge=0.0,
        le=100.0,
        description="Score at or above which match is 'very high confidence'",
    )
    low_confidence_threshold: float = Field(
        default=75.0,
        ge=0.0,
        le=100.0,
        description="Score below which match is flagged as 'low confidence'",
    )
    min_tokens_to_match: int = Field(
        default=2,
        ge=1,
        description="Minimum query tokens required before matching is attempted",
    )
    synonym_map: Dict[str, str] = Field(
        default_factory=dict,
        description="Maps variant spellings to canonical forms for normalization",
    )
    stopwords: Set[str] = Field(
        default_factory=set,
        description="Tokens to remove during normalization",
    )
    scorer_weights: Dict[str, float] = Field(
        default_factory=lambda: {
            "wratio": 0.30,
            "token_sort": 0.25,
            "token_set": 0.35,
            "partial": 0.10,
        },
        description="Weights for rapidfuzz scorers (wratio, token_sort, token_set, partial)",
    )
    max_tokens: int = Field(
        default=9,
        ge=1,
        description="Maximum query tokens to use (longest tokens preferred)",
    )
    max_combinations_per_level: int = Field(
        default=5000,
        ge=1,
        description="Cap on token combinations per candidate-generation level",
    )
