"""Service d'authentification et gestion des utilisateurs."""

from typing import Optional, Dict
from flask_jwt_extended import create_access_token, create_refresh_token
from models.user import User, db
from utils.security import hash_password, verify_password, generate_token
from schemas.user import UserRegisterSchema, UserLoginSchema


class AuthService:
    """Service pour la gestion de l'authentification."""
    
    @staticmethod
    def register_user(data: UserRegisterSchema) -> tuple[User, str, str]:
        """Inscrit un nouvel utilisateur.
        
        Args:
            data: Données d'inscription validées.
        
        Returns:
            Tuple (user, access_token, refresh_token).
        
        Raises:
            ValueError: Si l'email ou le username existe déjà.
        """
        # Vérifier que les mots de passe correspondent
        data.validate_passwords_match()
        
        # Vérifier si l'email existe déjà
        existing_user = User.query.filter_by(email=data.email).first()
        if existing_user:
            raise ValueError("Cette adresse email est déjà utilisée")
        
        # Vérifier si le username existe déjà
        existing_username = User.query.filter_by(username=data.username).first()
        if existing_username:
            raise ValueError("Ce nom d'utilisateur est déjà pris")
        
        # Créer l'utilisateur
        user = User(
            email=data.email,
            username=data.username,
            hashed_password=hash_password(data.password),
            is_active=True,
            is_verified=False,  # Nécessite vérification email (à implémenter)
            verification_token=generate_token()
        )
        
        db.session.add(user)
        db.session.commit()
        
        # Générer les tokens JWT
        access_token = create_access_token(identity=user.id)
        refresh_token = create_refresh_token(identity=user.id)
        
        return user, access_token, refresh_token
    
    @staticmethod
    def login_user(data: UserLoginSchema) -> tuple[User, str, str]:
        """Connecte un utilisateur.
        
        Args:
            data: Données de connexion validées.
        
        Returns:
            Tuple (user, access_token, refresh_token).
        
        Raises:
            ValueError: Si les credentials sont invalides.
        """
        # Trouver l'utilisateur par email
        user = User.query.filter_by(email=data.email).first()
        
        if not user:
            raise ValueError("Email ou mot de passe incorrect")
        
        # Vérifier le mot de passe
        if not verify_password(data.password, user.hashed_password):
            raise ValueError("Email ou mot de passe incorrect")
        
        # Vérifier que le compte est actif
        if not user.is_active:
            raise ValueError("Ce compte a été désactivé")
        
        # Générer les tokens JWT
        access_token = create_access_token(identity=user.id)
        refresh_token = create_refresh_token(identity=user.id)
        
        return user, access_token, refresh_token
    
    @staticmethod
    def get_user_by_id(user_id: str) -> Optional[User]:
        """Récupère un utilisateur par son ID.
        
        Args:
            user_id: ID de l'utilisateur.
        
        Returns:
            User ou None si non trouvé.
        """
        return User.query.get(user_id)
    
    @staticmethod
    def update_user(user: User, **kwargs: Dict) -> User:
        """Met à jour les informations d'un utilisateur.
        
        Args:
            user: Utilisateur à mettre à jour.
            **kwargs: Champs à mettre à jour.
        
        Returns:
            User mis à jour.
        
        Raises:
            ValueError: Si le nouveau username ou email existe déjà.
        """
        # Vérifier le username si fourni
        if 'username' in kwargs and kwargs['username'] != user.username:
            existing = User.query.filter_by(username=kwargs['username']).first()
            if existing:
                raise ValueError("Ce nom d'utilisateur est déjà pris")
            user.username = kwargs['username']
        
        # Vérifier l'email si fourni
        if 'email' in kwargs and kwargs['email'] != user.email:
            existing = User.query.filter_by(email=kwargs['email']).first()
            if existing:
                raise ValueError("Cette adresse email est déjà utilisée")
            user.email = kwargs['email']
            user.is_verified = False  # Nécessite re-vérification
        
        db.session.commit()
        return user

