"""
Authentication endpoints
"""
from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import OAuth2PasswordBearer, OAuth2PasswordRequestForm
from sqlalchemy.orm import Session
from typing import Any
from datetime import timedelta
from uuid import UUID

from app.db.session import get_db
from app.core.config import settings
from app.core.security import (
    create_access_token,
    create_refresh_token,
    verify_password,
    get_password_hash,
    generate_verification_code,
    verify_token
)
from app.models.user import User, EmailVerificationToken
from app.schemas.auth import Token, UserLogin, UserRegister, VerifyEmail, ForgotPassword, ResetPassword

router = APIRouter()
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="token")


@router.post("/register", response_model=dict)
async def register_user(
    user_data: UserRegister,
    db: Session = Depends(get_db)
) -> Any:
    """Register a new user"""
    
    # Check if user already exists
    existing_user = db.query(User).filter(User.email == user_data.email).first()
    if existing_user:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Email already registered"
        )
    
    # Create new user
    user = User(
        email=user_data.email,
        password_hash=get_password_hash(user_data.password),
        first_name=user_data.first_name,
        last_name=user_data.last_name,
        phone=user_data.phone,
        role_id=UUID('00000000-0000-0000-0000-000000000005')  # Default role: customer
    )
    
    db.add(user)
    db.commit()
    db.refresh(user)
    
    # Generate verification code
    verification_code = generate_verification_code()
    
    # Save verification token
    token = EmailVerificationToken(
        user_id=user.user_id,
        token=verification_code,
        token_type="email_verification",
        expires_at=None  # Will be set by service
    )
    
    db.add(token)
    db.commit()
    
    # TODO: Send verification email
    
    return {
        "message": "User registered successfully. Please check your email for verification code.",
        "user_id": str(user.user_id)
    }


@router.post("/login", response_model=Token)
async def login_user(
    form_data: OAuth2PasswordRequestForm = Depends(),
    db: Session = Depends(get_db)
) -> Any:
    """User login"""
    
    # Find user by email
    user = db.query(User).filter(User.email == form_data.username).first()
    
    if not user or not verify_password(form_data.password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Incorrect email or password",
            headers={"WWW-Authenticate": "Bearer"},
        )
    
    if not user.is_active:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="User account is inactive"
        )
    
    if not user.is_email_verified:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Email not verified. Please verify your email first."
        )
    
    # Create access token
    access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
    access_token = create_access_token(
        data={"sub": str(user.user_id)}, expires_delta=access_token_expires
    )
    
    # Create refresh token
    refresh_token = create_refresh_token(data={"sub": str(user.user_id)})
    
    # Check if user is admin to determine redirect
    is_admin = user.role and user.role.role_name == 'admin'
    
    return {
        "access_token": access_token,
        "refresh_token": refresh_token,
        "token_type": "bearer",
        "is_admin": is_admin
    }


@router.post("/verify-email")
async def verify_email(
    verification_data: VerifyEmail,
    db: Session = Depends(get_db)
) -> Any:
    """Verify user email with code"""
    
    # Find verification token
    token = db.query(EmailVerificationToken).filter(
        EmailVerificationToken.token == verification_data.verification_code,
        EmailVerificationToken.token_type == "email_verification",
        EmailVerificationToken.is_used == False
    ).first()
    
    if not token:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid or expired verification code"
        )
    
    # Get user
    user = db.query(User).filter(User.user_id == token.user_id).first()
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    # Update user verification status
    user.is_email_verified = True
    token.is_used = True
    
    db.commit()
    
    return {"message": "Email verified successfully"}


@router.post("/forgot-password")
async def forgot_password(
    forgot_data: ForgotPassword,
    db: Session = Depends(get_db)
) -> Any:
    """Send password reset code to user email"""
    
    # Find user
    user = db.query(User).filter(User.email == forgot_data.email).first()
    if not user:
        # Don't reveal if email exists or not
        return {"message": "If the email exists, a reset code has been sent."}
    
    # Generate reset code
    reset_code = generate_verification_code()
    
    # Save reset token
    token = EmailVerificationToken(
        user_id=user.user_id,
        token=reset_code,
        token_type="password_reset",
        expires_at=None  # Will be set by service
    )
    
    db.add(token)
    db.commit()
    
    # TODO: Send reset email
    
    return {"message": "If the email exists, a reset code has been sent."}


@router.post("/reset-password")
async def reset_password(
    reset_data: ResetPassword,
    db: Session = Depends(get_db)
) -> Any:
    """Reset user password with code"""
    
    # Find reset token
    token = db.query(EmailVerificationToken).filter(
        EmailVerificationToken.token == reset_data.reset_code,
        EmailVerificationToken.token_type == "password_reset",
        EmailVerificationToken.is_used == False
    ).first()
    
    if not token:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="Invalid or expired reset code"
        )
    
    # Get user
    user = db.query(User).filter(User.user_id == token.user_id).first()
    if not user:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="User not found"
        )
    
    # Update password
    user.password_hash = get_password_hash(reset_data.new_password)
    token.is_used = True
    
    db.commit()
    
    return {"message": "Password reset successfully"}


@router.post("/refresh", response_model=Token)
async def refresh_token(
    refresh_token: str,
    db: Session = Depends(get_db)
) -> Any:
    """Refresh access token"""
    
    try:
        payload = verify_token(refresh_token)
        user_id = payload.get("sub")
        
        if not user_id or payload.get("type") != "refresh":
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="Invalid refresh token"
            )
        
        # Verify user exists and is active
        user = db.query(User).filter(User.user_id == UUID(user_id)).first()
        if not user or not user.is_active:
            raise HTTPException(
                status_code=status.HTTP_401_UNAUTHORIZED,
                detail="User not found or inactive"
            )
        
        # Create new access token
        access_token_expires = timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
        access_token = create_access_token(
            data={"sub": str(user.user_id)}, expires_delta=access_token_expires
        )
        
        return {
            "access_token": access_token,
            "refresh_token": refresh_token,  # Keep the same refresh token
            "token_type": "bearer"
        }
        
    except Exception:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid refresh token"
        )