from fastapi import APIRouter, Depends, Request, Query from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy.orm import selectinload from ..database import get_db from ..models import Set, Card router = APIRouter() templates = Jinja2Templates(directory="app/templates") @router.get("/", response_class=HTMLResponse) async def index(request: Request, db: AsyncSession = Depends(get_db)): result = await db.execute(select(Set).order_by(Set.code)) sets = result.scalars().all() return templates.TemplateResponse("index.html", {"request": request, "sets": sets}) @router.get("/sets", response_class=HTMLResponse) async def list_sets(request: Request, db: AsyncSession = Depends(get_db)): result = await db.execute(select(Set).order_by(Set.code)) sets = result.scalars().all() return templates.TemplateResponse("sets.html", {"request": request, "sets": sets}) @router.get("/sets/{set_code}", response_class=HTMLResponse) async def set_detail(request: Request, set_code: str, db: AsyncSession = Depends(get_db)): result = await db.execute( select(Set).where(Set.code == set_code.upper()).options(selectinload(Set.cards)) ) s = result.scalar_one_or_none() if not s: return templates.TemplateResponse("404.html", {"request": request}, status_code=404) return templates.TemplateResponse("set_detail.html", {"request": request, "set": s}) @router.get("/search", response_class=HTMLResponse) async def search_page(request: Request): return templates.TemplateResponse("search.html", {"request": request}) @router.get("/api/search") async def search_cards( q: str = Query(""), db: AsyncSession = Depends(get_db), ): """Search cards by full code (e.g. CRI-068) or by name.""" q = q.strip() # Try full-code search: CODE-NUMBER if "-" in q: parts = q.split("-", 1) code_part = parts[0].strip().upper() num_part = parts[1].strip().lstrip("0") # remove leading zeros stmt = ( select(Card) .join(Card.set) .where(Set.code == code_part, Card.number == num_part) .options(selectinload(Card.set)) ) else: # Search by name stmt = ( select(Card) .join(Card.set) .where(Card.name.ilike(f"%{q}%")) .options(selectinload(Card.set)) .limit(50) ) result = await db.execute(stmt) cards = result.scalars().all() return [ { "id": c.id, "full_code": c.full_code, "name": c.name, "type": c.type or "", "rarity": c.rarity or "", "set_name": c.set.name, } for c in cards ] @router.get("/api/sets") async def api_list_sets(db: AsyncSession = Depends(get_db)): result = await db.execute(select(Set).order_by(Set.code)) sets = result.scalars().all() return [ {"code": s.code, "name": s.name, "release_date": s.release_date or "", "card_count": len(s.cards)} for s in sets ] @router.get("/api/sets/{set_code}/cards") async def api_set_cards(set_code: str, db: AsyncSession = Depends(get_db)): result = await db.execute( select(Set).where(Set.code == set_code.upper()).options(selectinload(Set.cards)) ) s = result.scalar_one_or_none() if not s: return [] return [ {"id": c.id, "number": c.number, "name": c.name, "type": c.type or "", "rarity": c.rarity or "", "hp": c.hp, "full_code": c.full_code} for c in s.cards ]