package dev.lions.user.manager.service;

import dev.lions.user.manager.dto.role.RoleAssignmentDTO;
import dev.lions.user.manager.dto.role.RoleDTO;
import dev.lions.user.manager.enums.role.TypeRole;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;

import java.util.List;
import java.util.Optional;

/**
 * Service de gestion des rôles Keycloak
 * Utilise uniquement l'API Admin Keycloak (AUCUN accès direct à la DB)
 */
public interface RoleService {

    /**
     * Récupère tous les rôles d'un realm
     * @param realmName nom du realm
     * @return liste des rôles
     */
    List<RoleDTO> getAllRealmRoles(@NotBlank String realmName);

    /**
     * Récupère tous les rôles d'un client
     * @param realmName nom du realm
     * @param clientName nom du client
     * @return liste des rôles
     */
    List<RoleDTO> getAllClientRoles(@NotBlank String realmName, @NotBlank String clientName);

    /**
     * Récupère un rôle par son ID
     * @param roleId ID du rôle
     * @param realmName nom du realm
     * @param typeRole type de rôle (REALM ou CLIENT)
     * @param clientName nom du client (si CLIENT_ROLE)
     * @return rôle ou Optional vide
     */
    Optional<RoleDTO> getRoleById(@NotBlank String roleId,
                                  @NotBlank String realmName,
                                  @NotNull TypeRole typeRole,
                                  String clientName);

    /**
     * Récupère un rôle par son nom
     * @param roleName nom du rôle
     * @param realmName nom du realm
     * @param typeRole type de rôle (REALM ou CLIENT)
     * @param clientName nom du client (si CLIENT_ROLE)
     * @return rôle ou Optional vide
     */
    Optional<RoleDTO> getRoleByName(@NotBlank String roleName,
                                    @NotBlank String realmName,
                                    @NotNull TypeRole typeRole,
                                    String clientName);

    /**
     * Crée un nouveau rôle realm
     * @param role données du rôle
     * @param realmName nom du realm
     * @return rôle créé
     */
    RoleDTO createRealmRole(@Valid @NotNull RoleDTO role, @NotBlank String realmName);

    /**
     * Crée un nouveau rôle client
     * @param role données du rôle
     * @param realmName nom du realm
     * @param clientName nom du client
     * @return rôle créé
     */
    RoleDTO createClientRole(@Valid @NotNull RoleDTO role,
                            @NotBlank String realmName,
                            @NotBlank String clientName);

    /**
     * Met à jour un rôle
     * @param roleId ID du rôle
     * @param role données modifiées
     * @param realmName nom du realm
     * @param typeRole type de rôle
     * @param clientName nom du client (si CLIENT_ROLE)
     * @return rôle mis à jour
     */
    RoleDTO updateRole(@NotBlank String roleId,
                      @Valid @NotNull RoleDTO role,
                      @NotBlank String realmName,
                      @NotNull TypeRole typeRole,
                      String clientName);

    /**
     * Supprime un rôle
     * @param roleId ID du rôle
     * @param realmName nom du realm
     * @param typeRole type de rôle
     * @param clientName nom du client (si CLIENT_ROLE)
     */
    void deleteRole(@NotBlank String roleId,
                   @NotBlank String realmName,
                   @NotNull TypeRole typeRole,
                   String clientName);

    /**
     * Assigne des rôles à un utilisateur
     * @param assignment données d'attribution
     */
    void assignRolesToUser(@Valid @NotNull RoleAssignmentDTO assignment);

    /**
     * Révoque des rôles d'un utilisateur
     * @param assignment données de révocation
     */
    void revokeRolesFromUser(@Valid @NotNull RoleAssignmentDTO assignment);

    /**
     * Récupère les rôles realm d'un utilisateur
     * @param userId ID de l'utilisateur
     * @param realmName nom du realm
     * @return liste des rôles
     */
    List<RoleDTO> getUserRealmRoles(@NotBlank String userId, @NotBlank String realmName);

    /**
     * Récupère les rôles client d'un utilisateur
     * @param userId ID de l'utilisateur
     * @param realmName nom du realm
     * @param clientName nom du client
     * @return liste des rôles
     */
    List<RoleDTO> getUserClientRoles(@NotBlank String userId,
                                     @NotBlank String realmName,
                                     @NotBlank String clientName);

    /**
     * Récupère tous les rôles d'un utilisateur (realm + clients)
     * @param userId ID de l'utilisateur
     * @param realmName nom du realm
     * @return liste des rôles
     */
    List<RoleDTO> getAllUserRoles(@NotBlank String userId, @NotBlank String realmName);

    /**
     * Ajoute un rôle composite
     * @param parentRoleId ID du rôle parent
     * @param childRoleIds IDs des rôles enfants à ajouter
     * @param realmName nom du realm
     * @param typeRole type du rôle parent
     * @param clientName nom du client (si CLIENT_ROLE)
     */
    void addCompositeRoles(@NotBlank String parentRoleId,
                          @NotNull List<String> childRoleIds,
                          @NotBlank String realmName,
                          @NotNull TypeRole typeRole,
                          String clientName);

    /**
     * Retire un rôle composite
     * @param parentRoleId ID du rôle parent
     * @param childRoleIds IDs des rôles enfants à retirer
     * @param realmName nom du realm
     * @param typeRole type du rôle parent
     * @param clientName nom du client (si CLIENT_ROLE)
     */
    void removeCompositeRoles(@NotBlank String parentRoleId,
                             @NotNull List<String> childRoleIds,
                             @NotBlank String realmName,
                             @NotNull TypeRole typeRole,
                             String clientName);

    /**
     * Récupère les rôles composites d'un rôle
     * @param roleId ID du rôle
     * @param realmName nom du realm
     * @param typeRole type de rôle
     * @param clientName nom du client (si CLIENT_ROLE)
     * @return liste des rôles composites
     */
    List<RoleDTO> getCompositeRoles(@NotBlank String roleId,
                                    @NotBlank String realmName,
                                    @NotNull TypeRole typeRole,
                                    String clientName);

    /**
     * Compte le nombre d'utilisateurs ayant un rôle
     * @param roleId ID du rôle
     * @param realmName nom du realm
     * @param typeRole type de rôle
     * @param clientName nom du client (si CLIENT_ROLE)
     * @return nombre d'utilisateurs
     */
    long countUsersWithRole(@NotBlank String roleId,
                           @NotBlank String realmName,
                           @NotNull TypeRole typeRole,
                           String clientName);

    /**
     * Vérifie si un rôle existe
     * @param roleName nom du rôle
     * @param realmName nom du realm
     * @param typeRole type de rôle
     * @param clientName nom du client (si CLIENT_ROLE)
     * @return true si existe
     */
    boolean roleExists(@NotBlank String roleName,
                      @NotBlank String realmName,
                      @NotNull TypeRole typeRole,
                      String clientName);

    /**
     * Vérifie si un utilisateur a un rôle spécifique
     * @param userId ID de l'utilisateur
     * @param roleName nom du rôle
     * @param realmName nom du realm
     * @param typeRole type de rôle
     * @param clientName nom du client (si CLIENT_ROLE)
     * @return true si l'utilisateur a le rôle
     */
    boolean userHasRole(@NotBlank String userId,
                       @NotBlank String roleName,
                       @NotBlank String realmName,
                       @NotNull TypeRole typeRole,
                       String clientName);
}
