# ============================================================
# Authentication API — login / me / logout
# ============================================================
from datetime import datetime, timezone
from typing import Annotated

from fastapi import APIRouter, Depends, HTTPException, status
from fastapi.security import HTTPBearer, HTTPAuthorizationCredentials
from pydantic import BaseModel
from sqlalchemy import select
from sqlalchemy.orm import Session

from app.core.database import get_db
from app.core.models import User, UserRole, UserStatus
from app.core.security import (
    verify_password,
    create_jwt_token,
    decode_jwt_token,
)


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


# -------------------- Pydantic models --------------------
class LoginRequest(BaseModel):
    username: str
    password: str


class UserResponse(BaseModel):
    id: int
    username: str
    display_name: str | None
    role: str
    status: str

    class Config:
        from_attributes = True


class LoginResponse(BaseModel):
    access_token: str
    token_type: str = "bearer"
    user: UserResponse


# -------------------- Bearer security --------------------
security = HTTPBearer()


# -------------------- Dependencies --------------------
async def get_current_user(
    credentials: Annotated[HTTPAuthorizationCredentials, Depends(security)],
    db: Session = Depends(get_db),
) -> User:
    """
    Validate Bearer JWT token, query User from DB, check status.
    """
    credentials_exception = HTTPException(
        status_code=status.HTTP_401_UNAUTHORIZED,
        detail="Invalid or expired token",
        headers={"WWW-Authenticate": "Bearer"},
    )
    try:
        payload = decode_jwt_token(credentials.credentials)
    except HTTPException:
        raise credentials_exception

    user_id = payload.get("sub")
    if user_id is None:
        raise credentials_exception

    user = db.execute(
        select(User).where(User.id == int(user_id))
    ).scalar_one_or_none()

    if user is None:
        raise credentials_exception

    if user.status != UserStatus.active:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User account is disabled",
        )

    return user


# -------------------- Endpoints --------------------
@router.post("/login", response_model=LoginResponse)
async def login(data: LoginRequest, db: Session = Depends(get_db)):
    """Authenticate user and return JWT + user info."""
    user = db.execute(
        select(User).where(User.username == data.username)
    ).scalar_one_or_none()

    if not user or not verify_password(data.password, user.password_hash):
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid username or password",
        )

    if user.status != UserStatus.active:
        raise HTTPException(
            status_code=status.HTTP_403_FORBIDDEN,
            detail="User account is disabled",
        )

    # Update last_login_at
    user.last_login_at = datetime.now(timezone.utc)
    db.commit()

    # Create JWT
    role_val = user.role.value if hasattr(user.role, "value") else user.role
    token = create_jwt_token({
        "sub": str(user.id),
        "username": user.username,
        "role": role_val,
    })

    return LoginResponse(
        access_token=token,
        token_type="bearer",
        user=UserResponse(
            id=user.id,
            username=user.username,
            display_name=user.display_name,
            role=role_val,
            status=user.status.value if hasattr(user.status, "value") else user.status,
        ),
    )


@router.get("/me", response_model=UserResponse)
async def get_me(user: User = Depends(get_current_user)):
    """Return current logged-in user info."""
    return UserResponse(
        id=user.id,
        username=user.username,
        display_name=user.display_name,
        role=user.role.value if hasattr(user.role, "value") else user.role,
        status=user.status.value if hasattr(user.status, "value") else user.status,
    )


@router.post("/logout")
async def logout(user: User = Depends(get_current_user)):
    """
    Logout endpoint. Token invalidation is client-side;
    server confirms the token was valid and user is authenticated.
    """
    return {"message": "Logged out successfully", "user_id": user.id}