from fastapi import APIRouter, Depends, HTTPException, Query from pydantic import BaseModel from typing import Optional from sqlalchemy.ext.asyncio import AsyncSession from app.database import get_db from app.api.v1.deps import get_current_user_id from app.services.credit import CreditService from app.services.payment import PaymentService router = APIRouter() class PurchaseRequest(BaseModel): package_id: str pay_type: str = "alipay" class SubscribeRequest(BaseModel): plan_id: str pay_type: str = "alipay" @router.get("/balance") async def get_balance( user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): svc = CreditService(db) return await svc.get_balance(user_id) @router.get("/history") async def get_history( page: int = Query(1, ge=1), size: int = Query(20, ge=1, le=100), user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): svc = CreditService(db) return await svc.get_history(user_id, page, size) @router.get("/packages") async def list_packages( db: AsyncSession = Depends(get_db), ): svc = CreditService(db) return await svc.get_packages() @router.get("/subscription-plans") async def list_subscription_plans( user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): svc = CreditService(db) return await svc.get_subscription_plans() @router.post("/purchase") async def purchase_package( req: PurchaseRequest, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): svc = CreditService(db) packages = await svc.get_packages() pkg = next((p for p in packages if p["id"] == req.package_id), None) if not pkg: raise HTTPException(status_code=404, detail="次数包不存在") pay_svc = PaymentService(db) order = await pay_svc.create_credit_order( user_id=user_id, amount=pkg["price"], description=f"购买 {pkg['name']} ({pkg['credits']}次)", pay_type=req.pay_type, metadata={"credit_package_id": req.package_id, "credits": pkg["credits"]}, ) return order @router.post("/subscribe") async def subscribe_plan( req: SubscribeRequest, user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): svc = CreditService(db) plans = await svc.get_subscription_plans() plan = next((p for p in plans if p["id"] == req.plan_id), None) if not plan: raise HTTPException(status_code=404, detail="订阅套餐不存在") pay_svc = PaymentService(db) order = await pay_svc.create_credit_order( user_id=user_id, amount=plan["price"], description=f"开通 {plan['name']} (每月{plan['credits_per_month']}次)", pay_type=req.pay_type, metadata={"subscription_plan_id": req.plan_id, "credits_per_month": plan["credits_per_month"]}, ) return order @router.post("/cancel-subscription") async def cancel_subscription( user_id: str = Depends(get_current_user_id), db: AsyncSession = Depends(get_db), ): from app.models.user_credit import UserCredit from sqlalchemy import select result = await db.execute(select(UserCredit).where(UserCredit.user_id == user_id)) uc = result.scalar_one_or_none() if not uc or not uc.subscription_plan_id: raise HTTPException(status_code=400, detail="没有有效的订阅") uc.subscription_auto_renew = False await db.flush() return {"success": True, "message": "已取消自动续费,当前订阅到期后不再续费"}