"""Desires & Bounties router.""" from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Query, status from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select from app.database import get_db from app.models import User, Desire from app.schemas import DesireCreate, DesirePublic from app.middleware.auth import get_current_user, require_tier router = APIRouter() @router.get("", response_model=list[DesirePublic]) async def list_desires( status_filter: str | None = Query(None, alias="status"), min_heat: float = Query(0, ge=0), limit: int = Query(20, ge=1, le=50), offset: int = Query(0, ge=0), db: AsyncSession = Depends(get_db), ): query = select(Desire).where(Desire.heat_score >= min_heat) if status_filter: query = query.where(Desire.status == status_filter) else: query = query.where(Desire.status == "open") query = query.order_by(Desire.heat_score.desc()).limit(limit).offset(offset) result = await db.execute(query) return result.scalars().all() @router.get("/{desire_id}", response_model=DesirePublic) async def get_desire(desire_id: UUID, db: AsyncSession = Depends(get_db)): result = await db.execute(select(Desire).where(Desire.id == desire_id)) desire = result.scalar_one_or_none() if not desire: raise HTTPException(status_code=404, detail="Desire not found") return desire @router.post("", response_model=DesirePublic, status_code=status.HTTP_201_CREATED) async def create_desire( body: DesireCreate, db: AsyncSession = Depends(get_db), user: User = Depends(require_tier("pro", "studio")), ): desire = Desire( author_id=user.id, prompt_text=body.prompt_text, style_hints=body.style_hints, ) db.add(desire) await db.flush() # TODO: Embed prompt text (Track G) # TODO: Check similarity clustering (Track G) # TODO: Enqueue process_desire worker job (Track G) return desire @router.post("/{desire_id}/fulfill", status_code=status.HTTP_200_OK) async def fulfill_desire( desire_id: UUID, shader_id: UUID = Query(..., description="Shader that fulfills this desire"), db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user), ): """Mark a desire as fulfilled by a shader. (Track G)""" desire = (await db.execute(select(Desire).where(Desire.id == desire_id))).scalar_one_or_none() if not desire: raise HTTPException(status_code=404, detail="Desire not found") if desire.status != "open": raise HTTPException(status_code=400, detail="Desire is not open") from datetime import datetime, timezone desire.status = "fulfilled" desire.fulfilled_by_shader = shader_id desire.fulfilled_at = datetime.now(timezone.utc) return {"status": "fulfilled", "desire_id": desire_id, "shader_id": shader_id} @router.post("/{desire_id}/tip") async def tip_desire( desire_id: UUID, db: AsyncSession = Depends(get_db), user: User = Depends(require_tier("pro", "studio")), ): """Add a tip to a bounty. (Track H — stub)""" raise HTTPException( status_code=status.HTTP_501_NOT_IMPLEMENTED, detail="Bounty tipping coming in M4" )