"""Pydantic models for request validation.

Defines typed models for all web route inputs with automatic validation.
"""
from __future__ import annotations

from typing import Optional, List
from pydantic import BaseModel, ConfigDict, Field, field_validator, model_validator
from enum import Enum


class PowerBracket(int, Enum):
    """Power bracket enumeration (1-4)."""
    BRACKET_1 = 1
    BRACKET_2 = 2
    BRACKET_3 = 3
    BRACKET_4 = 4


class DeckMode(str, Enum):
    """Deck building mode."""
    STANDARD = "standard"
    RANDOM = "random"
    HEADLESS = "headless"


class OwnedMode(str, Enum):
    """Owned cards usage mode."""
    OFF = "off"
    PREFER = "prefer"
    ONLY = "only"


class CommanderPartnerType(str, Enum):
    """Commander partner configuration type."""
    SINGLE = "single"
    PARTNER = "partner"
    BACKGROUND = "background"
    PARTNER_WITH = "partner_with"


class BuildRequest(BaseModel):
    """Build request validation model."""
    
    commander: str = Field(..., min_length=1, max_length=200, description="Commander card name")
    themes: List[str] = Field(default_factory=list, max_length=5, description="Theme tags")
    power_bracket: PowerBracket = Field(default=PowerBracket.BRACKET_2, description="Power bracket (1-4)")
    
    # Partner configuration
    partner_mode: Optional[CommanderPartnerType] = Field(default=None, description="Partner type")
    partner_name: Optional[str] = Field(default=None, max_length=200, description="Partner commander name")
    background_name: Optional[str] = Field(default=None, max_length=200, description="Background name")
    
    # Owned cards
    owned_mode: OwnedMode = Field(default=OwnedMode.OFF, description="Owned cards mode")
    
    # Custom theme
    custom_theme_name: Optional[str] = Field(default=None, max_length=100, description="Custom theme name")
    custom_theme_tags: Optional[List[str]] = Field(default=None, max_length=20, description="Custom theme tags")
    
    # Include/exclude lists
    must_include: Optional[List[str]] = Field(default=None, max_length=99, description="Must-include card names")
    must_exclude: Optional[List[str]] = Field(default=None, max_length=500, description="Must-exclude card names")
    
    # Random modes
    random_commander: bool = Field(default=False, description="Randomize commander")
    random_themes: bool = Field(default=False, description="Randomize themes")
    random_seed: Optional[int] = Field(default=None, ge=0, description="Random seed")
    
    @field_validator("commander")
    @classmethod
    def validate_commander_not_empty(cls, v: str) -> str:
        """Ensure commander name is not just whitespace."""
        if not v or not v.strip():
            raise ValueError("Commander name cannot be empty")
        return v.strip()
    
    @field_validator("themes")
    @classmethod
    def validate_themes_unique(cls, v: List[str]) -> List[str]:
        """Ensure themes are unique and non-empty."""
        if not v:
            return []
        
        cleaned = [t.strip() for t in v if t and t.strip()]
        seen = set()
        unique = []
        for theme in cleaned:
            lower = theme.lower()
            if lower not in seen:
                seen.add(lower)
                unique.append(theme)
        
        return unique
    
    @model_validator(mode="after")
    def validate_partner_consistency(self) -> "BuildRequest":
        """Validate partner configuration consistency."""
        if self.partner_mode == CommanderPartnerType.PARTNER:
            if not self.partner_name:
                raise ValueError("Partner mode requires partner_name")
        
        if self.partner_mode == CommanderPartnerType.BACKGROUND:
            if not self.background_name:
                raise ValueError("Background mode requires background_name")
        
        if self.partner_name and not self.partner_mode:
            raise ValueError("partner_name requires partner_mode to be set")
        
        if self.background_name and self.partner_mode != CommanderPartnerType.BACKGROUND:
            raise ValueError("background_name only valid with background partner_mode")
        
        return self
    
    @model_validator(mode="after")
    def validate_custom_theme_consistency(self) -> "BuildRequest":
        """Validate custom theme requires both name and tags."""
        if self.custom_theme_name and not self.custom_theme_tags:
            raise ValueError("Custom theme requires both name and tags")
        
        if self.custom_theme_tags and not self.custom_theme_name:
            raise ValueError("Custom theme tags require theme name")
        
        return self


class CommanderSearchRequest(BaseModel):
    """Commander search/validation request."""
    
    query: str = Field(..., min_length=1, max_length=200, description="Search query")
    limit: int = Field(default=10, ge=1, le=100, description="Maximum results")
    
    @field_validator("query")
    @classmethod
    def validate_query_not_empty(cls, v: str) -> str:
        """Ensure query is not just whitespace."""
        if not v or not v.strip():
            raise ValueError("Search query cannot be empty")
        return v.strip()


class ThemeValidationRequest(BaseModel):
    """Theme validation request."""
    
    themes: List[str] = Field(..., min_length=1, max_length=10, description="Themes to validate")
    
    @field_validator("themes")
    @classmethod
    def validate_themes_not_empty(cls, v: List[str]) -> List[str]:
        """Ensure themes are not empty."""
        cleaned = [t.strip() for t in v if t and t.strip()]
        if not cleaned:
            raise ValueError("At least one valid theme required")
        return cleaned


class OwnedCardsImportRequest(BaseModel):
    """Owned cards import request."""
    
    format_type: str = Field(..., pattern="^(csv|txt|arena)$", description="File format")
    content: str = Field(..., min_length=1, description="File content")
    
    @field_validator("content")
    @classmethod
    def validate_content_not_empty(cls, v: str) -> str:
        """Ensure content is not empty."""
        if not v or not v.strip():
            raise ValueError("File content cannot be empty")
        return v


class BatchBuildRequest(BaseModel):
    """Batch build request for multiple variations."""
    
    base_config: BuildRequest = Field(..., description="Base build configuration")
    count: int = Field(..., ge=1, le=10, description="Number of builds to generate")
    variation_seed: Optional[int] = Field(default=None, ge=0, description="Seed for variations")
    
    @field_validator("count")
    @classmethod
    def validate_count_reasonable(cls, v: int) -> int:
        """Ensure batch count is reasonable."""
        if v > 10:
            raise ValueError("Batch count cannot exceed 10")
        return v


class CardReplacementRequest(BaseModel):
    """Card replacement request for compliance."""
    
    card_name: str = Field(..., min_length=1, max_length=200, description="Card to replace")
    reason: Optional[str] = Field(default=None, max_length=500, description="Replacement reason")
    
    @field_validator("card_name")
    @classmethod
    def validate_card_name_not_empty(cls, v: str) -> str:
        """Ensure card name is not empty."""
        if not v or not v.strip():
            raise ValueError("Card name cannot be empty")
        return v.strip()


class DeckExportRequest(BaseModel):
    """Deck export request."""
    
    format_type: str = Field(..., pattern="^(csv|txt|json|arena)$", description="Export format")
    include_commanders: bool = Field(default=True, description="Include commanders in export")
    include_lands: bool = Field(default=True, description="Include lands in export")
    
    model_config = ConfigDict(use_enum_values=True)
