from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy.ext.asyncio import AsyncSession from app.config import settings from app.database import get_db from app.dependencies import get_current_admin from app.schemas.activity import AdminActivityUpsertRequest from app.services.activity_match_service import ( build_activity_share_api_url, build_activity_share_link, build_activity_share_path, build_activity_url_link, ensure_activity_share_qrcode, ensure_activity_share_token, refresh_activity_share_assets, ) from app.services.admin_service import get_system_config_value from app.services.activity_service import ( create_activity, delete_activity, get_admin_activity_registration_detail, get_activity_by_id, list_admin_activities, toggle_publish_activity, update_activity, ) router = APIRouter() @router.get("") async def get_activities( admin_payload: dict = Depends(get_current_admin), session: AsyncSession = Depends(get_db), ) -> dict: _ = admin_payload activities = await list_admin_activities(session) api_base_url = await get_system_config_value(session, "api_base_url", "") public_site_url = settings.public_site_url or api_base_url.replace("/api/v1", "").rstrip("/") data = [] for item in activities: item = await ensure_activity_share_token(session, item) item = await ensure_activity_share_qrcode(session, item) data.append( { "id": item.id, "title": item.title, "description": item.description, "category": item.category, "location": item.location, "cover_image": item.cover_image, "start_time": item.start_time.isoformat() if item.start_time else None, "end_time": item.end_time.isoformat() if item.end_time else None, "signup_deadline": item.signup_deadline.isoformat() if item.signup_deadline else None, "match_deadline": item.match_deadline.isoformat() if item.match_deadline else None, "status": item.status, "is_published": item.is_published, "capacity_male": item.capacity_male, "capacity_female": item.capacity_female, "match_window_hours": item.match_window_hours, "selection_limit": item.selection_limit, "require_audit": item.require_audit, "share_token": item.share_token, "share_qr_url": item.share_qr_url, "share_path": await build_activity_share_path(session, item), "share_link": await build_activity_share_link(session, item, public_site_url=public_site_url), "share_api_url": await build_activity_share_api_url(session, item, api_base_url=api_base_url), "share_url_link": await build_activity_url_link(session, item), "share_url_link_error": item.share_url_link_error, } ) return {"code": 0, "message": "ok", "data": data} @router.post("/{activity_id}/refresh-share-assets") async def refresh_share_assets( activity_id: int, admin_payload: dict = Depends(get_current_admin), session: AsyncSession = Depends(get_db), ) -> dict: _ = admin_payload activity = await get_activity_by_id(session, activity_id) if activity is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Activity not found") activity = await refresh_activity_share_assets(session, activity) api_base_url = await get_system_config_value(session, "api_base_url", "") public_site_url = settings.public_site_url or api_base_url.replace("/api/v1", "").rstrip("/") return { "code": 0, "message": "ok", "data": { "id": activity.id, "share_qr_url": activity.share_qr_url, "share_path": await build_activity_share_path(session, activity), "share_link": await build_activity_share_link(session, activity, public_site_url=public_site_url), "share_api_url": await build_activity_share_api_url(session, activity, api_base_url=api_base_url), "share_url_link": activity.share_url_link, "share_url_link_error": activity.share_url_link_error, }, } @router.post("") async def create( payload: AdminActivityUpsertRequest, admin_payload: dict = Depends(get_current_admin), session: AsyncSession = Depends(get_db), ) -> dict: activity = await create_activity(session, payload, int(admin_payload["admin_id"])) return {"code": 0, "message": "ok", "data": {"id": activity.id}} @router.put("/{activity_id}") async def update( activity_id: int, payload: AdminActivityUpsertRequest, admin_payload: dict = Depends(get_current_admin), session: AsyncSession = Depends(get_db), ) -> dict: _ = admin_payload activity = await get_activity_by_id(session, activity_id) if activity is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Activity not found") try: updated = await update_activity(session, activity, payload) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"code": 0, "message": "ok", "data": {"id": updated.id}} @router.put("/{activity_id}/publish") async def publish( activity_id: int, admin_payload: dict = Depends(get_current_admin), session: AsyncSession = Depends(get_db), ) -> dict: _ = admin_payload activity = await get_activity_by_id(session, activity_id) if activity is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Activity not found") updated = await toggle_publish_activity(session, activity) return {"code": 0, "message": "ok", "data": {"id": updated.id, "is_published": updated.is_published}} @router.delete("/{activity_id}") async def delete( activity_id: int, admin_payload: dict = Depends(get_current_admin), session: AsyncSession = Depends(get_db), ) -> dict: _ = admin_payload activity = await get_activity_by_id(session, activity_id) if activity is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Activity not found") try: await delete_activity(session, activity) except ValueError as exc: raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail=str(exc)) from exc return {"code": 0, "message": "ok", "data": {"id": activity_id}} @router.get("/{activity_id}/registrations") async def registrations( activity_id: int, admin_payload: dict = Depends(get_current_admin), session: AsyncSession = Depends(get_db), ) -> dict: _ = admin_payload activity = await get_activity_by_id(session, activity_id) if activity is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Activity not found") data = await get_admin_activity_registration_detail(session, activity) return {"code": 0, "message": "ok", "data": data}