# backend/app/routers/trip.py from fastapi import APIRouter, Depends, HTTPException from sqlmodel import Session, select from ..agents.travel_agent import run_planner from ..auth.deps import current_user from ..auth.scope import scoped from ..db import get_session from ..models import ( Person, SavedTrip, Trip, TripChecklist, TripDay, TripPrep, TripRoute, TripStay, ) from ..schemas import ( PlanRequest, PlanResultOut, SavedTripOut, UpcomingTripOut, WatchToggleRequest, ) router = APIRouter() def _saved_out(r: SavedTrip) -> SavedTripOut: return SavedTripOut( id=r.id, title=r.title, tag=r.tag, note=r.note, now=r.now, delta=r.delta, down=r.down, watch=r.watch, hint=r.hint, spark=r.spark, ) @router.get("/trip/upcoming", response_model=UpcomingTripOut) def upcoming(s: Session = Depends(get_session), user: Person = Depends(current_user)): trip = s.exec(scoped(select(Trip), Trip, user.id)).first() if not trip: raise HTTPException(404, "no trip") routes = { r.dir: { "mode": r.mode, "from": r.from_st, "ft": r.ft, "to": r.to_st, "tt": r.tt, "seat": r.seat, "note": r.note, } for r in s.exec(select(TripRoute).where(TripRoute.trip_id == trip.id)).all() } stay = s.exec(select(TripStay).where(TripStay.trip_id == trip.id)).first() preps = s.exec( select(TripPrep).where(TripPrep.trip_id == trip.id).order_by(TripPrep.sort_order) ).all() days = s.exec( select(TripDay).where(TripDay.trip_id == trip.id).order_by(TripDay.sort_order) ).all() checks = s.exec( select(TripChecklist) .where(TripChecklist.trip_id == trip.id) .order_by(TripChecklist.sort_order) ).all() # check 그룹화 (group → items[]) groups: list[dict] = [] gindex: dict[str, int] = {} for c in checks: if c.group not in gindex: gindex[c.group] = len(groups) groups.append({"name": c.group, "items": []}) item = {"id": c.id, "text": c.text} if c.auto: item["auto"] = c.auto groups[gindex[c.group]]["items"].append(item) return UpcomingTripOut( trip={ "id": trip.id, "dday": trip.dday, "title": trip.title, "dates": trip.dates, "purpose": trip.purpose, "brief": trip.brief, "weather": trip.weather, }, route=routes, stay=({"name": stay.name, "desc": stay.desc, "conf": stay.conf} if stay else {}), prep=[{"text": p.text, "state": p.state} for p in preps], days=[{"id": d.id, "tab": d.tab, "items": d.items} for d in days], check=groups, expense={ "budget": trip.expense_budget, "planned": trip.expense_planned, "rows": trip.expense_rows, "note": trip.expense_note, }, ) @router.get("/trip/saved", response_model=list[SavedTripOut]) def saved(s: Session = Depends(get_session)): rows = s.exec(select(SavedTrip).order_by(SavedTrip.sort_order)).all() return [_saved_out(r) for r in rows] @router.post("/trip/saved/{sid}/watch", response_model=SavedTripOut) def toggle_watch(sid: str, req: WatchToggleRequest, s: Session = Depends(get_session)): r = s.get(SavedTrip, sid) if not r: raise HTTPException(404, "no saved trip") r.watch = req.watch if req.watch is not None else (not r.watch) s.add(r) s.commit() s.refresh(r) return _saved_out(r) @router.post("/trip/plan", response_model=PlanResultOut) def plan(req: PlanRequest, s: Session = Depends(get_session)): return run_planner(s, req.text)