from datetime import datetime, timedelta, timezone from fastapi import APIRouter, Depends, HTTPException, status from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from app.core.deps import get_current_active_user, get_db from app.models.membership import MembershipPlan, UserMembership from app.models.user import User from app.schemas.membership import MembershipPlanOut, PurchaseMembership, UserMembershipOut router = APIRouter() @router.get("/plans", response_model=list[MembershipPlanOut]) async def list_plans(db: AsyncSession = Depends(get_db)): result = await db.execute( select(MembershipPlan) .where(MembershipPlan.is_active == True) .order_by(MembershipPlan.sort_order.asc()) ) return result.scalars().all() @router.get("/me", response_model=UserMembershipOut | None) async def get_my_membership( current_user: User = Depends(get_current_active_user), db: AsyncSession = Depends(get_db), ): now = datetime.now(timezone.utc) result = await db.execute( select(UserMembership).where( UserMembership.user_id == current_user.id, UserMembership.is_active == True, UserMembership.end_date >= now, ).order_by(UserMembership.end_date.desc()).limit(1) ) return result.scalar_one_or_none() @router.post("/purchase", response_model=UserMembershipOut) async def purchase_membership( payload: PurchaseMembership, current_user: User = Depends(get_current_active_user), db: AsyncSession = Depends(get_db), ): plan_result = await db.execute( select(MembershipPlan).where( MembershipPlan.id == payload.plan_id, MembershipPlan.is_active == True, ) ) plan = plan_result.scalar_one_or_none() if not plan: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="会员方案不存在或已下架") now = datetime.now(timezone.utc) existing = await db.execute( select(UserMembership).where( UserMembership.user_id == current_user.id, UserMembership.is_active == True, UserMembership.end_date >= now, ).order_by(UserMembership.end_date.desc()).limit(1) ) current_membership = existing.scalar_one_or_none() start = current_membership.end_date if current_membership else now end = start + timedelta(days=plan.duration_days) membership = UserMembership( user_id=current_user.id, plan_id=plan.id, start_date=start, end_date=end, is_active=True, ) db.add(membership) await db.commit() await db.refresh(membership) return membership