from fastapi import Depends, HTTPException, status, Header from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials from typing import Optional from app.database import get_supabase from app.config import settings import logging logger = logging.getLogger(__name__) security = HTTPBearer(auto_error=False) async def get_current_user( credentials: Optional[HTTPAuthorizationCredentials] = Depends(security), ): """Extract and verify the current user from Supabase JWT""" if not credentials: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Not authenticated", ) token = credentials.credentials supabase = get_supabase() try: response = supabase.auth.get_user(token) if not response or not response.user: raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token", ) return response.user except Exception as e: logger.error(f"Auth error: {e}") raise HTTPException( status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid or expired token", ) async def get_optional_user( credentials: Optional[HTTPAuthorizationCredentials] = Depends(security), ): """Optional auth - returns None if not authenticated""" if not credentials: return None try: return await get_current_user(credentials) except HTTPException: return None async def get_user_subscription(user=Depends(get_current_user)): """Get user's subscription plan""" supabase = get_supabase() try: result = ( supabase.table("subscriptions") .select("*") .eq("user_id", user.id) .eq("status", "active") .execute() ) if result.data: return result.data[0] return {"plan": "free", "status": "active", "user_id": user.id} except Exception: return {"plan": "free", "status": "active", "user_id": user.id} async def require_plan(min_plan: str, user=Depends(get_current_user)): """Require a minimum plan level""" plan_order = ["free", "starter", "business", "agency", "enterprise"] subscription = await get_user_subscription(user) user_plan = subscription.get("plan", "free") if plan_order.index(user_plan) < plan_order.index(min_plan): raise HTTPException( status_code=status.HTTP_402_PAYMENT_REQUIRED, detail=f"This feature requires {min_plan} plan or higher", ) return user