"""
Translation Dictionary Data Models

Pydantic models for translation dictionary system.
"""

from datetime import datetime, timezone
from enum import Enum
from typing import Any, Dict, List, Optional
from uuid import uuid4

from pydantic import BaseModel, Field, ConfigDict, field_validator


class TranslationSource(str, Enum):
    """Source types for translation dictionaries."""

    FIGMA = "figma"
    CSS = "css"
    SCSS = "scss"
    HEROUI = "heroui"
    SHADCN = "shadcn"
    TAILWIND = "tailwind"
    JSON = "json"
    CUSTOM = "custom"


class MappingType(str, Enum):
    """Types of mappings in a translation dictionary."""

    TOKEN = "token"
    COMPONENT = "component"
    PATTERN = "pattern"


class TokenMapping(BaseModel):
    """Single token mapping from source to DSS canonical."""

    model_config = ConfigDict(extra="forbid")

    source_token: str = Field(
        ..., description="Source token name (e.g., '--brand-blue', '$primary-color')"
    )
    dss_token: str = Field(
        ..., description="DSS canonical token path (e.g., 'color.primary.500')"
    )
    source_value: Optional[str] = Field(None, description="Original value from source (for reference)")
    notes: Optional[str] = Field(None, description="Human-readable notes about this mapping")
    confidence: float = Field(
        default=1.0, ge=0.0, le=1.0, description="Confidence score for auto-generated mappings"
    )
    auto_generated: bool = Field(default=False, description="Whether this mapping was auto-generated")


class ComponentMapping(BaseModel):
    """Single component mapping from source to DSS canonical."""

    model_config = ConfigDict(extra="forbid")

    source_component: str = Field(
        ..., description="Source component (e.g., '.btn-primary', 'HeroButton')"
    )
    dss_component: str = Field(
        ..., description="DSS canonical component (e.g., 'Button[variant=primary]')"
    )
    prop_mappings: Dict[str, str] = Field(default_factory=dict, description="Prop name mappings (source -> DSS)")
    notes: Optional[str] = Field(None)


class PatternMapping(BaseModel):
    """Pattern mapping for structural translations."""

    model_config = ConfigDict(extra="forbid")

    source_pattern: str = Field(..., description="Source pattern (e.g., 'form-row', 'card-grid')")
    dss_pattern: str = Field(..., description="DSS canonical pattern")
    notes: Optional[str] = Field(None)


class CustomProp(BaseModel):
    """Custom property not in DSS core."""

    model_config = ConfigDict(extra="forbid")

    name: str = Field(..., description="Token name in DSS namespace (e.g., 'color.brand.acme.primary')")
    value: Any = Field(..., description="Token value")
    type: str = Field(default="string", description="Value type (color, dimension, string, etc.)")
    description: Optional[str] = Field(None)
    deprecated: bool = Field(default=False)
    deprecated_message: Optional[str] = Field(None)


class TranslationMappings(BaseModel):
    """Container for all mapping types."""

    model_config = ConfigDict(extra="forbid")

    tokens: Dict[str, str] = Field(
        default_factory=dict, description="Token mappings: source_token -> dss_token"
    )
    components: Dict[str, str] = Field(
        default_factory=dict, description="Component mappings: source_component -> dss_component"
    )
    patterns: Dict[str, str] = Field(default_factory=dict, description="Pattern mappings: source_pattern -> dss_pattern")


class TranslationDictionary(BaseModel):
    """Complete translation dictionary for a project."""

    model_config = ConfigDict(extra="forbid")

    # Metadata
    schema_version: str = Field(
        default="dss-translation-v1", alias="$schema", description="Schema version identifier"
    )
    uuid: str = Field(default_factory=lambda: str(uuid4()), description="Unique identifier for this dictionary")
    project: str = Field(..., description="Project identifier")
    source: TranslationSource = Field(..., description="Source type for this dictionary")
    version: str = Field(default="1.0.0", description="Dictionary version")
    created_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
    updated_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))

    # Mappings
    mappings: TranslationMappings = Field(
        default_factory=TranslationMappings, description="All mappings from source to DSS"
    )

    # Custom extensions
    custom_props: Dict[str, Any] = Field(default_factory=dict, description="Custom props not in DSS core (namespaced)")

    # Tracking
    unmapped: List[str] = Field(default_factory=list, description="Source tokens that couldn't be mapped")
    notes: List[str] = Field(default_factory=list, description="Human-readable notes")

    @field_validator("custom_props")
    @classmethod
    def validate_custom_props_namespace(cls, v: Dict[str, Any]) -> Dict[str, Any]:
        """Ensure custom props use proper namespacing."""
        for key in v.keys():
            # Custom props should be namespaced (e.g., color.brand.acme.primary)
            if "." not in key:
                raise ValueError(
                    f"Custom prop '{key}' must use dot-notation namespace "
                    "(e.g., 'color.brand.project.name')"
                )
        return v


class TranslationRegistry(BaseModel):
    """In-memory registry of all loaded translation dictionaries."""

    model_config = ConfigDict(arbitrary_types_allowed=True)

    dictionaries: Dict[str, TranslationDictionary] = Field(
        default_factory=dict, description="Loaded dictionaries by source type"
    )
    combined_token_map: Dict[str, str] = Field(default_factory=dict, description="Combined source->DSS token mappings")
    combined_component_map: Dict[str, str] = Field(
        default_factory=dict, description="Combined source->DSS component mappings"
    )
    all_custom_props: Dict[str, Any] = Field(default_factory=dict, description="Merged custom props from all dictionaries")
    conflicts: List[Dict[str, Any]] = Field(default_factory=list, description="Detected mapping conflicts")


class ResolvedToken(BaseModel):
    """A fully resolved token with provenance."""

    model_config = ConfigDict(extra="forbid")

    dss_path: str = Field(..., description="DSS canonical path (e.g., 'color.primary.500')")
    value: Any = Field(..., description="Resolved value")
    source_token: Optional[str] = Field(None, description="Original source token if translated")
    source_type: Optional[TranslationSource] = Field(None, description="Source type if translated")
    is_custom: bool = Field(default=False, description="Whether this is a custom prop")
    provenance: List[str] = Field(default_factory=list, description="Resolution chain for debugging")


class ResolvedTheme(BaseModel):
    """Fully resolved theme with all translations applied."""

    model_config = ConfigDict(arbitrary_types_allowed=True)

    name: str
    version: str = "1.0.0"
    base_theme: str = Field(..., description="Base theme name (light/dark)")
    tokens: Dict[str, ResolvedToken] = Field(default_factory=dict)
    custom_props: Dict[str, ResolvedToken] = Field(default_factory=dict)
    translations_applied: List[str] = Field(default_factory=list, description="List of translation dictionaries applied")
    resolved_at: datetime = Field(default_factory=lambda: datetime.now(timezone.utc))
