"""
Gestion de l'authentification et des sessions sécurisées pour Versailles Airsoft.
Hachage des mots de passe avec bcrypt et sessions signées avec itsdangerous.
"""

import os
from typing import Optional
import bcrypt
from itsdangerous import URLSafeTimedSerializer, BadSignature, SignatureExpired
from fastapi import Request, Depends, HTTPException, status
from sqlalchemy.orm import Session

from database import get_db
from models import User

# Clé secrète issue du fichier d'environnement
SECRET_KEY = os.getenv("SECRET_KEY", "versailles_default_secret_key_tactical_2026")
COOKIE_NAME = "airsoft_session"
SESSION_MAX_AGE = 60 * 60 * 24 * 7  # 7 jours en secondes

serializer = URLSafeTimedSerializer(SECRET_KEY)


def hash_password(password: str) -> str:
    """Hache un mot de passe en clair à l'aide de bcrypt."""
    salt = bcrypt.gensalt()
    hashed = bcrypt.hashpw(password.encode("utf-8"), salt)
    return hashed.decode("utf-8")


def verify_password(plain_password: str, hashed_password: str) -> bool:
    """Vérifie si le mot de passe correspond au hash stocké."""
    try:
        return bcrypt.checkpw(plain_password.encode("utf-8"), hashed_password.encode("utf-8"))
    except Exception:
        return False


def create_session_token(user_id: int, username: str) -> str:
    """Génère un token de session chiffré/signé."""
    payload = {"user_id": user_id, "username": username}
    return serializer.dumps(payload)


def verify_session_token(token: str) -> Optional[dict]:
    """Décode et valide le token de session avec expiration."""
    try:
        data = serializer.loads(token, max_age=SESSION_MAX_AGE)
        return data
    except (BadSignature, SignatureExpired):
        return None


def get_current_user(request: Request, db: Session = Depends(get_db)) -> Optional[User]:
    """
    Récupère l'utilisateur actuellement connecté depuis le cookie de session.
    Retourne None si l'utilisateur n'est pas connecté ou si le token est invalide.
    """
    token = request.cookies.get(COOKIE_NAME)
    if not token:
        return None

    data = verify_session_token(token)
    if not data or "user_id" not in data:
        return None

    user = db.query(User).filter(User.id == data["user_id"]).first()
    return user


def require_user(request: Request, db: Session = Depends(get_db)) -> User:
    """
    Dépendance exigeant un utilisateur connecté.
    Lève une exception 401 si non authentifié.
    """
    user = get_current_user(request, db)
    if not user:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Connexion requise pour effectuer cette opération"
        )
    return user
