from typing import Any, Dict, List, Literal, Set
from dataclasses import dataclass, asdict
import datetime

@dataclass
class TravelRequest:
    destination_cities_ordered: List[str]
    start_date: datetime.datetime
    end_date: datetime.datetime
    must_have_pois: Set[str]
    maximum_num_of_days: int
    
    @classmethod
    def to_dict(cls, obj) -> Dict[str, Any]:
        """Convert dataclass instance to dictionary"""
        data = asdict(obj)
        # Convert datetime objects to ISO format strings
        if isinstance(data.get('start_date'), datetime.datetime):
            data['start_date'] = data['start_date'].isoformat()
        if isinstance(data.get('end_date'), datetime.datetime):
            data['end_date'] = data['end_date'].isoformat()
        # Convert sets to lists for JSON serialization
        if isinstance(data.get('must_have_pois'), set):
            data['must_have_pois'] = list(data['must_have_pois'])
        if isinstance(data.get('maximum_num_of_days'), int):
            data['maximum_num_of_days'] = data['maximum_num_of_days']
        return data
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'TravelRequest':
        """Create dataclass instance from dictionary"""
        # Convert ISO format strings back to datetime objects
        if isinstance(data.get('start_date'), str):
            data['start_date'] = datetime.datetime.fromisoformat(data['start_date'])
        if isinstance(data.get('end_date'), str):
            data['end_date'] = datetime.datetime.fromisoformat(data['end_date'])
        if isinstance(data.get('maximum_num_of_days'), int):
            data['maximum_num_of_days'] = data['maximum_num_of_days']
        # Convert lists back to sets
        if isinstance(data.get('must_have_pois'), list):
            data['must_have_pois'] = set(data['must_have_pois'])
        return cls(**data)

@dataclass
class DetailItem:
    type: Literal["transportation", "hotel", "poi"]
    id: str
    name: str
    
    @classmethod
    def to_dict(cls, obj) -> Dict[str, Any]:
        """Convert dataclass instance to dictionary"""
        return asdict(obj)
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'DetailItem':
        """Create dataclass instance from dictionary"""
        return cls(**data)

@dataclass
class ScheduleDetail:
    period: Literal["Morning", "Afternoon", "Evening"]
    description: str
    detailList: List[DetailItem]
    
    @classmethod
    def to_dict(cls, obj) -> Dict[str, Any]:
        """Convert dataclass instance to dictionary"""
        data = asdict(obj)
        # Convert DetailItem objects to dictionaries
        if isinstance(data.get('detailList'), list):
            data['detailList'] = [DetailItem.to_dict(item) for item in obj.detailList]
        return data
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'ScheduleDetail':
        """Create dataclass instance from dictionary"""
        # Convert DetailItem dictionaries back to objects
        if isinstance(data.get('detailList'), list):
            data['detailList'] = [DetailItem.from_dict(item) for item in data['detailList']]
        return cls(**data)

@dataclass
class DayInfo:
    day: int
    scheduleTitle: str
    tips: str
    scheduleDetail: List[ScheduleDetail]
    
    @classmethod
    def to_dict(cls, obj) -> Dict[str, Any]:
        """Convert dataclass instance to dictionary"""
        data = asdict(obj)
        # Convert ScheduleDetail objects to dictionaries
        if isinstance(data.get('scheduleDetail'), list):
            data['scheduleDetail'] = [ScheduleDetail.to_dict(item) for item in obj.scheduleDetail]
        return data
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'DayInfo':
        """Create dataclass instance from dictionary"""
        # Convert ScheduleDetail dictionaries back to objects
        if isinstance(data.get('scheduleDetail'), list):
            data['scheduleDetail'] = [ScheduleDetail.from_dict(item) for item in data['scheduleDetail']]
        return cls(**data)

@dataclass
class Itinerary:
    itineraryName: str
    dayInfos: List[DayInfo]
    
    @classmethod
    def to_dict(cls, obj) -> Dict[str, Any]:
        """Convert dataclass instance to dictionary"""
        data = asdict(obj)
        # Convert DayInfo objects to dictionaries
        if isinstance(data.get('dayInfos'), list):
            data['dayInfos'] = [DayInfo.to_dict(item) for item in obj.dayInfos]
        return data
    
    @classmethod
    def from_dict(cls, data: Dict[str, Any]) -> 'Itinerary':
        """Create dataclass instance from dictionary"""
        # Convert DayInfo dictionaries back to objects
        if isinstance(data.get('dayInfos'), list):
            data['dayInfos'] = [DayInfo.from_dict(item) for item in data['dayInfos']]
        return cls(**data)
    
OptimizationObjective = Literal["user_preference"] 