from enum import Enum
from typing import Literal, Optional

from pydantic import BaseModel, ConfigDict, Field, model_validator


def to_camel(value: str) -> str:
    parts = value.split("_")
    return parts[0] + "".join(part.capitalize() for part in parts[1:])


class APIModel(BaseModel):
    model_config = ConfigDict(alias_generator=to_camel, populate_by_name=True)


class Duration(str, Enum):
    HALF_DAY = "half_day"
    FULL_DAY = "full_day"


class Pace(str, Enum):
    RELAXED = "relaxed"
    MODERATE = "moderate"
    COMPACT = "compact"


class Transport(str, Enum):
    WALKING = "walking"
    DRIVING = "driving"
    PUBLIC_TRANSPORT = "public_transport"


class BudgetLevel(str, Enum):
    ECONOMY = "economy"
    STANDARD = "standard"
    QUALITY = "quality"


Theme = Literal["亲子", "情侣", "朋友", "银发", "研学"]
Interest = Literal["自然风光", "文化场馆", "生态科普", "美食", "摄影"]


class TravelPreferences(APIModel):
    destination: Literal["深圳市光明区"] = "深圳市光明区"
    themes: list[Theme] = Field(default_factory=list)
    duration: Duration
    pace: Pace
    interests: list[Interest] = Field(default_factory=list)
    adults: int = Field(default=2, ge=0, le=20)
    children: int = Field(default=0, ge=0, le=20)
    child_ages: list[int] = Field(default_factory=list)
    transport: Transport = Transport.PUBLIC_TRANSPORT
    budget_level: BudgetLevel = BudgetLevel.STANDARD
    extra_requirements: str = Field(default="", max_length=500)

    @model_validator(mode="after")
    def validate_group_and_preferences(self) -> "TravelPreferences":
        if self.adults + self.children < 1:
            raise ValueError("出行总人数至少为1")
        if self.child_ages and len(self.child_ages) != self.children:
            raise ValueError("儿童年龄数量必须与儿童人数一致")
        if any(age < 0 or age > 17 for age in self.child_ages):
            raise ValueError("儿童年龄须在0至17岁之间")
        if not self.themes and not self.interests:
            raise ValueError("主题或特色偏好至少选择一项")
        return self


class ItineraryItem(APIModel):
    start_time: str
    end_time: str
    place_id: str
    place_name: str
    activity: str
    reason: str
    transfer_from_previous_minutes: Optional[int] = Field(default=None, ge=0)
    tips: list[str] = Field(default_factory=list)


class GeneratedItinerary(APIModel):
    title: str
    summary: str
    total_minutes: int = Field(ge=1, le=720)
    estimated_cost_text: str
    items: list[ItineraryItem] = Field(min_length=1, max_length=5)
    notes: list[str] = Field(default_factory=list)


class Source(APIModel):
    place_id: str
    source_name: str
    source_url: str
    updated_at: str


class Itinerary(GeneratedItinerary):
    sources: list[Source]


class PlanResponse(APIModel):
    conversation_id: str
    assistant_message: str
    itinerary: Itinerary
    change_summary: Optional[str] = None


class MessageRequest(APIModel):
    message: str = Field(min_length=1, max_length=500)


class HealthResponse(APIModel):
    status: str
    llm_mode: str
    model_configured: bool
    knowledge_count: int
