from pydantic import BaseModel from datetime import date from typing import Optional from enum import Enum class Cabin(str, Enum): economy = "economy" first = "first" class TripSearchRequest(BaseModel): origin: str # e.g. "JAX" or "GNV" destinations: list[str] # e.g. ["HNL", "LAX", "JFK"] earliest_departure: date latest_return: date party_size: int = 2 trip_duration_nights: int = 4 preferred_cabin: Cabin = Cabin.economy ihg_brands: list[str] = ["Kimpton", "InterContinental", "Hotel Indigo"] class FlightOption(BaseModel): destination: str outbound_date: date return_date: date fare_class: str # e.g. "L", "U", "Z" base_price: float # price for one ticket companion_taxes: float # taxes the companion pays (~$80) eligible_for_companion_cert: bool cabin: Cabin class HotelOption(BaseModel): destination: str property_name: str brand: str check_in: date check_out: date points_per_night: int total_points: int # for nights_paid only nights_paid: int nights_free: int # from 4th-night-free benefit cash_rate: Optional[float] = None # nightly cash rate if available class RestaurantOption(BaseModel): city: str name: str cuisine: str reservation_date: date party_size: int resy_credit_eligible: bool global_dining_access: bool class TripResult(BaseModel): destination: str flight: FlightOption hotel: Optional[HotelOption] = None restaurant: Optional[RestaurantOption] = None total_cash_out_of_pocket: float total_points_required: int benefits_captured: list[str] score: float # 0–100, higher = better value class SearchProgress(BaseModel): step: str # "delta" | "ihg" | "resy" | "done" message: str progress: int # 0–100 class SearchResponse(BaseModel): search_id: str results: list[TripResult]