"""Pydantic models for Tableau template manifests (canonical schema)."""

from __future__ import annotations

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

from pydantic import BaseModel, ConfigDict, Field


class CanonicalBaseModel(BaseModel):
    model_config = ConfigDict(extra="allow")


class CardinalityConstraint(CanonicalBaseModel):
    min: Optional[int] = None
    max: Optional[int] = None
    recommended_max: Optional[int] = None


class CanonicalRoleSpec(CanonicalBaseModel):
    id: str
    required: bool
    semantic_types: List[str]
    desired_type: Optional[str] = None
    cardinality: Optional[CardinalityConstraint] = None
    aggregation: Optional[List[str]] = None
    nullable: bool = True
    display_name: str
    description: str


class ValidationConstraint(CanonicalBaseModel):
    type: str
    role_id: str
    error_message: str
    allowed: Optional[List[str]] = None


class GrainSpec(CanonicalBaseModel):
    description: str
    row_count: Optional[CardinalityConstraint] = None


class MatchingHints(CanonicalBaseModel):
    user_intent_keywords: List[str] = Field(default_factory=list)
    example_prompts: List[str] = Field(default_factory=list)
    anti_patterns: List[str] = Field(default_factory=list)


class DatasourceConfig(CanonicalBaseModel):
    connection_type: Literal["hyper", "extract"] = "hyper"
    extract_relpath: str = "Data/Datasources/data.hyper"
    refresh_enabled: bool = False


class TemplateMetadata(CanonicalBaseModel):
    name: str
    display_name: str
    description: str
    viz_type: str
    tags: List[str] = Field(default_factory=list)
    version: str
    author: str = "g-gremlin"
    twb_file: str
    data_mode: Literal["aggregated", "raw"] = "aggregated"


class TemplateManifest(CanonicalBaseModel):
    schema_version: str = "2.0"
    template: TemplateMetadata
    canonical_roles: List[CanonicalRoleSpec]
    constraints: List[ValidationConstraint] = Field(default_factory=list)
    grain: Optional[GrainSpec] = None
    matching_hints: Optional[MatchingHints] = None
    datasource: DatasourceConfig = Field(default_factory=DatasourceConfig)


__all__ = [
    "CardinalityConstraint",
    "CanonicalRoleSpec",
    "ValidationConstraint",
    "GrainSpec",
    "MatchingHints",
    "DatasourceConfig",
    "TemplateMetadata",
    "TemplateManifest",
]
