"""Script Builder API endpoints.""" from typing import Annotated from uuid import UUID from fastapi import APIRouter, Depends, HTTPException, Request from sqlalchemy.ext.asyncio import AsyncSession from app.core.database import get_db from app.core.rate_limit import limiter from app.api.deps import get_current_active_user from app.models.user import User from app.schemas.script_builder import ( ScriptBuilderCreateRequest, ScriptBuilderMessageRequest, ScriptBuilderMessageResponse, ScriptBuilderSessionDetail, ScriptBuilderSessionSummary, SaveToLibraryRequest, ) from app.schemas.script_template import ScriptTemplateDetail from app.services import script_builder_service router = APIRouter(prefix="/scripts/builder", tags=["script-builder"]) MAX_SESSIONS_PER_USER = 5 @router.post("/sessions", response_model=ScriptBuilderSessionDetail, status_code=201) async def create_session( data: ScriptBuilderCreateRequest, db: Annotated[AsyncSession, Depends(get_db)], current_user: Annotated[User, Depends(get_current_active_user)], ) -> ScriptBuilderSessionDetail: """Start a new Script Builder session.""" # Enforce max concurrent sessions count = await script_builder_service.count_user_sessions(db, current_user.id) if count >= MAX_SESSIONS_PER_USER: raise HTTPException( status_code=400, detail=f"Maximum of {MAX_SESSIONS_PER_USER} builder sessions allowed. Delete an old session first.", ) session = await script_builder_service.create_session( db=db, user_id=current_user.id, team_id=current_user.team_id, language=data.language, ) await db.commit() return ScriptBuilderSessionDetail.model_validate(session) @router.get("/sessions", response_model=list[ScriptBuilderSessionSummary]) async def list_sessions( db: Annotated[AsyncSession, Depends(get_db)], current_user: Annotated[User, Depends(get_current_active_user)], limit: int = 20, offset: int = 0, ) -> list[ScriptBuilderSessionSummary]: """List user's recent builder sessions (lightweight, no messages).""" sessions = await script_builder_service.list_sessions( db=db, user_id=current_user.id, limit=limit, offset=offset ) return [ScriptBuilderSessionSummary.model_validate(s) for s in sessions] @router.get("/sessions/{session_id}", response_model=ScriptBuilderSessionDetail) async def get_session( session_id: UUID, db: Annotated[AsyncSession, Depends(get_db)], current_user: Annotated[User, Depends(get_current_active_user)], ) -> ScriptBuilderSessionDetail: """Get full session detail with message history.""" session = await script_builder_service.get_session(db, session_id, current_user.id) if not session: raise HTTPException(status_code=404, detail="Session not found") return ScriptBuilderSessionDetail.model_validate(session) @router.post( "/sessions/{session_id}/messages", response_model=ScriptBuilderMessageResponse, ) @limiter.limit("10/minute") async def send_message( request: Request, session_id: UUID, data: ScriptBuilderMessageRequest, db: Annotated[AsyncSession, Depends(get_db)], current_user: Annotated[User, Depends(get_current_active_user)], ) -> ScriptBuilderMessageResponse: """Send a message and get AI-generated script response.""" session = await script_builder_service.get_session(db, session_id, current_user.id) if not session: raise HTTPException(status_code=404, detail="Session not found") try: response = await script_builder_service.send_message(db, session, data.content) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) await db.commit() return response @router.delete("/sessions/{session_id}", status_code=204) async def delete_session( session_id: UUID, db: Annotated[AsyncSession, Depends(get_db)], current_user: Annotated[User, Depends(get_current_active_user)], ) -> None: """Delete a builder session.""" deleted = await script_builder_service.delete_session(db, session_id, current_user.id) if not deleted: raise HTTPException(status_code=404, detail="Session not found") await db.commit() @router.post( "/sessions/{session_id}/save", response_model=ScriptTemplateDetail, status_code=201, ) async def save_to_library( session_id: UUID, data: SaveToLibraryRequest, db: Annotated[AsyncSession, Depends(get_db)], current_user: Annotated[User, Depends(get_current_active_user)], ) -> ScriptTemplateDetail: """Save the latest generated script to the Script Library.""" session = await script_builder_service.get_session(db, session_id, current_user.id) if not session: raise HTTPException(status_code=404, detail="Session not found") try: template = await script_builder_service.save_to_library( db=db, session=session, name=data.name, description=data.description, category_id=data.category_id, share_with_team=data.share_with_team, user_id=current_user.id, team_id=current_user.team_id, ) except ValueError as e: raise HTTPException(status_code=400, detail=str(e)) await db.commit() await db.refresh(template) return ScriptTemplateDetail.model_validate(template)