from fastapi import APIRouter, Depends, HTTPException, Response from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import joinedload from app.core.database import get_session from app.models.encounter import Encounter from app.models.nuzlocke_run import NuzlockeRun from app.models.pokemon import Pokemon from app.models.route import Route from app.schemas.encounter import ( EncounterCreate, EncounterDetailResponse, EncounterResponse, EncounterUpdate, ) router = APIRouter() @router.post( "/runs/{run_id}/encounters", response_model=EncounterResponse, status_code=201, ) async def create_encounter( run_id: int, data: EncounterCreate, session: AsyncSession = Depends(get_session), ): # Validate run exists run = await session.get(NuzlockeRun, run_id) if run is None: raise HTTPException(status_code=404, detail="Run not found") # Validate route exists route = await session.get(Route, data.route_id) if route is None: raise HTTPException(status_code=404, detail="Route not found") # Validate pokemon exists pokemon = await session.get(Pokemon, data.pokemon_id) if pokemon is None: raise HTTPException(status_code=404, detail="Pokemon not found") encounter = Encounter( run_id=run_id, route_id=data.route_id, pokemon_id=data.pokemon_id, nickname=data.nickname, status=data.status, catch_level=data.catch_level, ) session.add(encounter) await session.commit() await session.refresh(encounter) return encounter @router.patch("/encounters/{encounter_id}", response_model=EncounterDetailResponse) async def update_encounter( encounter_id: int, data: EncounterUpdate, session: AsyncSession = Depends(get_session), ): encounter = await session.get(Encounter, encounter_id) if encounter is None: raise HTTPException(status_code=404, detail="Encounter not found") update_data = data.model_dump(exclude_unset=True) for field, value in update_data.items(): setattr(encounter, field, value) await session.commit() # Reload with relationships for detail response result = await session.execute( select(Encounter) .where(Encounter.id == encounter_id) .options( joinedload(Encounter.pokemon), joinedload(Encounter.current_pokemon), joinedload(Encounter.route), ) ) return result.scalar_one() @router.delete("/encounters/{encounter_id}", status_code=204) async def delete_encounter( encounter_id: int, session: AsyncSession = Depends(get_session) ): encounter = await session.get(Encounter, encounter_id) if encounter is None: raise HTTPException(status_code=404, detail="Encounter not found") await session.delete(encounter) await session.commit() return Response(status_code=204)