from fastapi import APIRouter, Depends, HTTPException from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from app.core.database import get_session from app.models.game import Game from app.models.genlocke import Genlocke, GenlockeLeg from app.models.nuzlocke_run import NuzlockeRun from app.schemas.genlocke import GenlockeCreate, GenlockeResponse router = APIRouter() @router.post("", response_model=GenlockeResponse, status_code=201) async def create_genlocke( data: GenlockeCreate, session: AsyncSession = Depends(get_session) ): if not data.game_ids: raise HTTPException(status_code=400, detail="At least one game is required") if not data.name.strip(): raise HTTPException(status_code=400, detail="Name is required") # Validate all game_ids exist result = await session.execute( select(Game).where(Game.id.in_(data.game_ids)) ) found_games = {g.id: g for g in result.scalars().all()} missing = [gid for gid in data.game_ids if gid not in found_games] if missing: raise HTTPException( status_code=404, detail=f"Games not found: {missing}" ) # Create genlocke genlocke = Genlocke( name=data.name.strip(), status="active", genlocke_rules=data.genlocke_rules, nuzlocke_rules=data.nuzlocke_rules, ) session.add(genlocke) await session.flush() # get genlocke.id # Create legs legs = [] for i, game_id in enumerate(data.game_ids, start=1): leg = GenlockeLeg( genlocke_id=genlocke.id, game_id=game_id, leg_order=i, ) session.add(leg) legs.append(leg) # Create the first run first_game = found_games[data.game_ids[0]] first_run = NuzlockeRun( game_id=first_game.id, name=f"{data.name.strip()} \u2014 Leg 1", status="active", rules=data.nuzlocke_rules, ) session.add(first_run) await session.flush() # get first_run.id # Link first leg to the run legs[0].run_id = first_run.id await session.commit() # Reload with relationships result = await session.execute( select(Genlocke) .where(Genlocke.id == genlocke.id) .options( selectinload(Genlocke.legs).selectinload(GenlockeLeg.game), ) ) return result.scalar_one()