from datetime import datetime, timezone

from fastapi import APIRouter, Depends, HTTPException, status
from sqlalchemy.orm import Session

from app.database import get_db
from app.dependencies import require_user_token
from app.models import PasswordResetToken, User, UserRole
from app.schemas import ForgotPasswordRequest, LoginRequest, Message, ResetPasswordRequest, Token
from app.security import hash_password, verify_password
from app.services.auth_service import authenticate, issue_token_for
from app.services.email_otp import create_password_reset_flow, send_otp_email

router = APIRouter(prefix="/auth", tags=["user-auth"])


@router.post("/login", response_model=Token)
def user_login(body: LoginRequest, db: Session = Depends(get_db)):
    user = authenticate(db, body.email, body.password)
    if not user or user.role != UserRole.user:
        raise HTTPException(status_code=status.HTTP_401_UNAUTHORIZED, detail="Invalid user credentials")
    if not user.is_active:
        raise HTTPException(status_code=status.HTTP_403_FORBIDDEN, detail="Inactive account")
    return Token(access_token=issue_token_for(user))


@router.post("/logout", response_model=Message)
def user_logout(_: User = Depends(require_user_token)):
    return Message(message="Logged out")


@router.post("/forgot-password", response_model=Message)
async def user_forgot_password(body: ForgotPasswordRequest, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.email == body.email, User.role == UserRole.user).first()
    if user:
        otp = create_password_reset_flow(db, user)
        await send_otp_email(user.email, otp)
    return Message(message="If an account exists for this email, an OTP has been sent.")


@router.post("/reset-password", response_model=Message)
def user_reset_password(body: ResetPasswordRequest, db: Session = Depends(get_db)):
    user = db.query(User).filter(User.email == body.email, User.role == UserRole.user).first()
    if not user:
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid request")

    token_row = (
        db.query(PasswordResetToken)
        .filter(PasswordResetToken.user_id == user.id, PasswordResetToken.used.is_(False))
        .order_by(PasswordResetToken.created_at.desc())
        .first()
    )
    if not token_row or not verify_password(body.otp, token_row.otp_hash):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="Invalid or expired OTP")

    if token_row.expires_at < datetime.now(timezone.utc):
        raise HTTPException(status_code=status.HTTP_400_BAD_REQUEST, detail="OTP expired")

    user.hashed_password = hash_password(body.new_password)
    token_row.used = True
    db.commit()
    return Message(message="Password updated")
