from fastapi import APIRouter, HTTPException, Depends, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.future import select
from src.config.database import get_db
from src.models.prediction import User
from src.schemas.auth_schema import SignupRequest, LoginRequest
from src.utils.auth import create_access_token, create_refresh_token, verify_access_token
from src.common.logger import logger
from passlib.context import CryptContext # type: ignore
from datetime import timedelta
import os
from dotenv import load_dotenv
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from src.utils.validate import validate_signup_request, validate_login_request
load_dotenv()
router = APIRouter()
pwd_context = CryptContext(schemes=["bcrypt"], deprecated="auto")
 
 
@router.post("/signup/")
async def signup_user(user: SignupRequest, db: AsyncSession = Depends(get_db)):
    try:
        logger.info(f"Signup attempt for email: {user.email}")
        
        # Validate all fields in one function call
        validate_signup_request(user)
        
        # Check if user already exists
        result = await db.execute(select(User).where(User.email == user.email))
        existing_user = result.scalar_one_or_none()
        if existing_user:
            raise HTTPException(
                status_code=status.HTTP_400_BAD_REQUEST, 
                detail="User already exists"
            )
        
        # Create new user
        hashed_password = pwd_context.hash(user.password)
        new_user = User(
            email=user.email,
            name=user.name,
            username=user.username,
            password=hashed_password,
            organization=user.organization
        )
        
        db.add(new_user)
        await db.commit()
        
        logger.info(f"User registered: {user.email}")
        return {"msg": "User created successfully"}
        
    except HTTPException:
        # Re-raise HTTP exceptions to preserve their status codes and details
        raise
    except Exception as e:
        logger.error(f"Error during signup for email {user.email}: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, 
            detail=f"Error: {str(e)}"
        )
 
 
@router.post("/login/")
async def login_user(credentials: LoginRequest, db: AsyncSession = Depends(get_db)):
    try:
        logger.info(f"Login attempt for email: {credentials.email}")
        
        # Validate login request
        validate_login_request(credentials)
        
        result = await db.execute(select(User).where(User.email == credentials.email))
        user = result.scalar_one_or_none()
        
        if not user or not pwd_context.verify(credentials.password, user.password):
            
            logger.warning(f"Login failed for {credentials.email}")
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED, 
                detail="Invalid email or password"
            )
        
        logger.info(f"Login successful for {credentials.email}")
        
        access_token = await create_access_token(
            data={"sub": user.email, "user_id": user.user_id},
            expires_delta=timedelta(minutes=int(os.getenv("ACCESS_TOKEN_EXPIRE_MINUTES", 30)))
        )
        
        refresh_token = await create_refresh_token(
            data={"sub": user.email, "user_id": user.user_id},
            expires_delta=timedelta(days=int(os.getenv("REFRESH_TOKEN_EXPIRE_DAYS", 7)))
        )
        
        return {
            "access_token": access_token,
            "refresh_token": refresh_token,
            "token_type": "bearer"
        }
        
    except HTTPException:
        # Re-raise HTTP exceptions to preserve their status codes and details
        raise
    except Exception as e:
        logger.error(f"Error during login for email {credentials.email}: {str(e)}")
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST, 
            detail=f"Error: {str(e)}"
        )
 
 
@router.post("/refresh/")
async def refresh_token(credentials: HTTPAuthorizationCredentials = Depends(HTTPBearer())):
    payload = await verify_access_token(credentials.credentials)
    if payload is None:
        raise HTTPException(status_code=401, detail="Invalid or expired refresh token")
 
    new_access_token = await create_access_token(
        data={"sub": payload["sub"], "user_id": payload["user_id"]}
    )
    return {"access_token": new_access_token, "token_type": "bearer"}