from typing import Optional from fastapi import APIRouter, Depends, HTTPException, status from pydantic import BaseModel, Field from sqlalchemy import select, text from sqlalchemy.ext.asyncio import AsyncSession from config import settings from deps import get_current_user from models import Character, Skill, User, get_db router = APIRouter(prefix="/character", tags=["character"]) class CharacterCreateIn(BaseModel): name: str = Field(min_length=3, max_length=32, pattern=r"^[A-Za-z0-9_]+$") class SkillOut(BaseModel): skill_name: str xp: int level: int class CharacterOut(BaseModel): id: int name: str level: int total_xp: int gold: int step_balance: int step_lifetime: int location_code: Optional[str] = None location_name: Optional[str] = None has_pending_event: bool = False skills: list[SkillOut] class Config: from_attributes = True async def _with_location(db: AsyncSession, char: Character) -> CharacterOut: out = CharacterOut.model_validate(char, from_attributes=True) out.has_pending_event = char.pending_event is not None if char.location_id is not None: row = (await db.execute(text( "SELECT code, name FROM locations WHERE id = :i" ), {"i": char.location_id})).first() if row: out.location_code, out.location_name = row[0], row[1] return out @router.post("", response_model=CharacterOut, status_code=status.HTTP_201_CREATED) async def create_character(data: CharacterCreateIn, user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)): exists = (await db.execute(select(Character).where(Character.user_id == user.id))).scalar_one_or_none() if exists: raise HTTPException(409, "Zaten bir karakterin var") name_taken = (await db.execute(select(Character).where(Character.name == data.name))).scalar_one_or_none() if name_taken: raise HTTPException(409, "Bu isim alınmış") char = Character(user_id=user.id, name=data.name) db.add(char) await db.flush() for skill_name in settings.SKILL_NAMES: db.add(Skill(character_id=char.id, skill_name=skill_name, xp=0, level=1)) # Başlangıç lokasyonu: köy. Not: başlangıç tool'u YOK — # ilk tool'lar köyde elle toplanan taş/sopa/sarmaşıktan craft edilir. start = (await db.execute(text( "SELECT id FROM locations WHERE type = 'village' ORDER BY id LIMIT 1" ))).first() if start: char.location_id = start[0] await db.commit() await db.refresh(char, ["skills"]) return await _with_location(db, char) @router.get("/me", response_model=CharacterOut) async def my_character(user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)): char = (await db.execute(select(Character).where(Character.user_id == user.id))).scalar_one_or_none() if not char: raise HTTPException(404, "Karakter yok, önce oluştur") await db.refresh(char, ["skills"]) return await _with_location(db, char)