"""Demo Requests — public POST from TapTrack Website, super admin manages.""" from datetime import datetime, timezone from typing import Optional from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from sqlalchemy.ext.asyncio import AsyncSession from sqlalchemy import select, desc from app.auth.dependencies import require_super_admin from app.database import get_db from app.models.user import HubUser from app.models.demo_request import DemoRequest router = APIRouter(prefix="/api/demo-requests", tags=["demo-requests"]) class DemoRequestSubmit(BaseModel): school: str contact: str phone: str class DemoRequestUpdate(BaseModel): status: Optional[str] = None # "new" | "contacted" | "converted" | "dismissed" notes: Optional[str] = None @router.post("", status_code=201) async def submit_demo_request( body: DemoRequestSubmit, db: AsyncSession = Depends(get_db), ): """Public endpoint — called by TapTrack Website form.""" req = DemoRequest( school_name=body.school, contact_person=body.contact, phone_or_email=body.phone, ) db.add(req) await db.commit() return {"ok": True, "id": req.id} @router.get("") async def list_demo_requests( status: Optional[str] = None, limit: int = 50, offset: int = 0, _admin: HubUser = Depends(require_super_admin), db: AsyncSession = Depends(get_db), ): """Super admin only — list all demo requests.""" stmt = select(DemoRequest).order_by(desc(DemoRequest.submitted_at)) if status: stmt = stmt.where(DemoRequest.status == status) stmt = stmt.limit(limit).offset(offset) items = (await db.execute(stmt)).scalars().all() return [ { "id": r.id, "school_name": r.school_name, "contact_person": r.contact_person, "phone_or_email": r.phone_or_email, "status": r.status, "notes": r.notes, "submitted_at": r.submitted_at.isoformat(), "updated_at": r.updated_at.isoformat(), } for r in items ] @router.put("/{req_id}") async def update_demo_request( req_id: str, body: DemoRequestUpdate, _admin: HubUser = Depends(require_super_admin), db: AsyncSession = Depends(get_db), ): """Super admin only — update status/notes on a demo request.""" req = (await db.execute(select(DemoRequest).where(DemoRequest.id == req_id))).scalar_one_or_none() if not req: raise HTTPException(404, detail="Demo request not found") if body.status is not None: valid_statuses = {"new", "contacted", "converted", "dismissed"} if body.status not in valid_statuses: raise HTTPException(400, detail=f"status must be one of: {', '.join(valid_statuses)}") req.status = body.status if body.notes is not None: req.notes = body.notes req.updated_at = datetime.now(timezone.utc) await db.commit() return { "id": req.id, "status": req.status, "notes": req.notes, "updated_at": req.updated_at.isoformat(), } @router.delete("/{req_id}", status_code=204) async def delete_demo_request( req_id: str, _admin: HubUser = Depends(require_super_admin), db: AsyncSession = Depends(get_db), ): """Super admin only — permanently delete a demo request.""" req = (await db.execute(select(DemoRequest).where(DemoRequest.id == req_id))).scalar_one_or_none() if not req: raise HTTPException(404, detail="Demo request not found") await db.delete(req) await db.commit()