package dev.lions.user.manager.client.view;

import dev.lions.user.manager.client.service.RoleServiceClient;
import dev.lions.user.manager.client.service.RealmServiceClient;
import dev.lions.user.manager.dto.role.RoleAssignmentDTO;
import dev.lions.user.manager.dto.role.RoleDTO;
import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.enums.role.TypeRole;
import jakarta.annotation.PostConstruct;
import jakarta.faces.application.FacesMessage;
import jakarta.faces.context.FacesContext;
import jakarta.faces.view.ViewScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import lombok.Data;
import org.eclipse.microprofile.rest.client.inject.RestClient;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Logger;
import java.util.stream.Collectors;

/**
 * Bean JSF pour la gestion des rôles
 */
@Named("roleGestionBean")
@ViewScoped
@Data
public class RoleGestionBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOGGER = Logger.getLogger(RoleGestionBean.class.getName());

    @Inject
    @RestClient
    private RoleServiceClient roleServiceClient;

    @Inject
    @RestClient
    private RealmServiceClient realmServiceClient;

    // Liste des rôles
    private List<RoleDTO> realmRoles = new ArrayList<>();
    private List<RoleDTO> clientRoles = new ArrayList<>();
    private List<RoleDTO> allRoles = new ArrayList<>();
    private RoleDTO selectedRole;
    private String selectedRoleName;

    // Pour la création/édition
    private RoleDTO newRole = RoleDTO.builder().build();
    private boolean editMode = false;

    // Filtres
    private String realmName = "lions-user-manager";
    private String clientName;
    private TypeRole selectedTypeRole;
    private String roleSearchText;

    // Options
    private List<TypeRole> typeRoleOptions = List.of(TypeRole.values());
    private List<String> availableRealms = new ArrayList<>();
    private List<String> availableClients = new ArrayList<>();

    @PostConstruct
    public void init() {
        loadRealms();
        loadRealmRoles();
    }

    /**
     * Charger les rôles Realm
     */
    public void loadRealmRoles() {
        if (realmName == null || realmName.isEmpty()) {
            LOGGER.warning("Realm non sélectionné, impossible de charger les rôles");
            addErrorMessage("Veuillez sélectionner un realm");
            return;
        }

        try {
            LOGGER.info("Chargement des rôles Realm pour le realm: " + realmName);
            realmRoles = roleServiceClient.getAllRealmRoles(realmName);
            updateAllRoles();
            loadClients();
            LOGGER.info("Chargement réussi: " + realmRoles.size() + " rôles Realm trouvés");
            if (realmRoles.isEmpty()) {
                addErrorMessage("Aucun rôle Realm trouvé dans le realm: " + realmName);
            }
        } catch (Exception e) {
            String errorMsg = "Erreur lors du chargement des rôles Realm pour le realm '" + realmName + "': "
                    + e.getMessage();
            LOGGER.severe(errorMsg);
            LOGGER.log(java.util.logging.Level.SEVERE, "Exception complète", e);
            addErrorMessage(errorMsg);
            realmRoles = new ArrayList<>();
            updateAllRoles();
        }
    }

    /**
     * Charger les rôles Client
     */
    public void loadClientRoles() {
        if (clientName == null || clientName.isEmpty()) {
            clientRoles = new ArrayList<>();
            updateAllRoles();
            return;
        }

        try {
            clientRoles = roleServiceClient.getAllClientRoles(clientName, realmName);
            updateAllRoles();
            LOGGER.info("Chargement de " + clientRoles.size() + " rôles Client");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des rôles Client: " + e.getMessage());
            addErrorMessage("Erreur lors du chargement des rôles Client");
        }
    }

    /**
     * Mettre à jour la liste complète des rôles
     */
    private void updateAllRoles() {
        allRoles = new ArrayList<>();
        allRoles.addAll(realmRoles);
        allRoles.addAll(clientRoles);
    }

    /**
     * Obtenir les rôles Realm filtrés par type
     */
    public List<RoleDTO> getFilteredRealmRoles() {
        if (selectedTypeRole == null) {
            return realmRoles;
        }
        return realmRoles.stream()
                .filter(r -> selectedTypeRole.equals(r.getTypeRole()))
                .collect(Collectors.toList());
    }

    /**
     * Obtenir les rôles Client filtrés par type
     */
    public List<RoleDTO> getFilteredClientRoles() {
        if (selectedTypeRole == null) {
            return clientRoles;
        }
        return clientRoles.stream()
                .filter(r -> selectedTypeRole.equals(r.getTypeRole()))
                .collect(Collectors.toList());
    }

    /**
     * Appliquer le filtre type (appelé depuis p:ajax)
     */
    public void applyTypeFilter() {
        // Les getFilteredRealmRoles/getFilteredClientRoles font le filtrage
        LOGGER.info("Filtre type appliqué: " + selectedTypeRole);
    }

    /**
     * Créer un nouveau rôle Realm
     */
    public void createRealmRole() {
        try {
            jakarta.ws.rs.core.Response response = roleServiceClient.createRealmRole(newRole, realmName);
            RoleDTO created = response.readEntity(RoleDTO.class);
            addSuccessMessage("Rôle Realm créé avec succès: " + created.getName());
            resetForm();
            loadRealmRoles();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la création: " + e.getMessage());
            addErrorMessage("Erreur lors de la création: " + e.getMessage());
        }
    }

    /**
     * Créer un nouveau rôle Client
     */
    public void createClientRole() {
        if (clientName == null || clientName.isEmpty()) {
            addErrorMessage("Le nom du client est obligatoire");
            return;
        }

        try {
            jakarta.ws.rs.core.Response response = roleServiceClient.createClientRole(clientName, newRole, realmName);
            RoleDTO created = response.readEntity(RoleDTO.class);
            addSuccessMessage("Rôle Client créé avec succès: " + created.getName());
            resetForm();
            loadClientRoles();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la création: " + e.getMessage());
            addErrorMessage("Erreur lors de la création: " + e.getMessage());
        }
    }

    /**
     * Supprimer un rôle Realm
     */
    public void deleteRealmRole(String roleName) {
        try {
            roleServiceClient.deleteRealmRole(roleName, realmName);
            addSuccessMessage("Rôle Realm supprimé avec succès: " + roleName);
            loadRealmRoles();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la suppression: " + e.getMessage());
            addErrorMessage("Erreur lors de la suppression: " + e.getMessage());
        }
    }

    /**
     * Supprimer un rôle Client
     */
    public void deleteClientRole(String roleName) {
        if (clientName == null || clientName.isEmpty()) {
            addErrorMessage("Le nom du client est obligatoire");
            return;
        }

        try {
            roleServiceClient.deleteClientRole(clientName, roleName, realmName);
            addSuccessMessage("Rôle Client supprimé avec succès: " + roleName);
            loadClientRoles();
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la suppression: " + e.getMessage());
            addErrorMessage("Erreur lors de la suppression: " + e.getMessage());
        }
    }

    /**
     * Attribuer un rôle à un utilisateur
     */
    public void assignRoleToUser(String userId, String roleName) {
        try {
            dev.lions.user.manager.dto.role.RoleAssignmentRequestDTO request = new dev.lions.user.manager.dto.role.RoleAssignmentRequestDTO(
                    List.of(roleName));

            roleServiceClient.assignRealmRoles(userId, realmName, request);
            addSuccessMessage("Rôle attribué avec succès");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de l'attribution: " + e.getMessage());
            addErrorMessage("Erreur lors de l'attribution: " + e.getMessage());
        }
    }

    /**
     * Révoquer un rôle d'un utilisateur
     */
    public void revokeRoleFromUser(String userId, String roleName) {
        try {
            dev.lions.user.manager.dto.role.RoleAssignmentRequestDTO request = new dev.lions.user.manager.dto.role.RoleAssignmentRequestDTO(
                    List.of(roleName));

            roleServiceClient.revokeRealmRoles(userId, realmName, request);
            addSuccessMessage("Rôle révoqué avec succès");
        } catch (Exception e) {
            LOGGER.severe("Erreur lors de la révocation: " + e.getMessage());
            addErrorMessage("Erreur lors de la révocation: " + e.getMessage());
        }
    }

    /**
     * Attribuer un rôle à un utilisateur (depuis les paramètres de requête)
     */
    public void assignRoleFromParams() {
        FacesContext context = FacesContext.getCurrentInstance();
        String userId = context.getExternalContext().getRequestParameterMap().get("userId");
        String roleName = context.getExternalContext().getRequestParameterMap().get("roleName");

        if (userId != null && roleName != null) {
            assignRoleToUser(userId, roleName);
        } else {
            addErrorMessage("Paramètres manquants: userId ou roleName");
        }
    }

    /**
     * Révoquer un rôle d'un utilisateur (depuis les paramètres de requête)
     */
    public void revokeRoleFromParams() {
        FacesContext context = FacesContext.getCurrentInstance();
        String userId = context.getExternalContext().getRequestParameterMap().get("userId");
        String roleName = context.getExternalContext().getRequestParameterMap().get("roleName");

        if (userId != null && roleName != null) {
            revokeRoleFromUser(userId, roleName);
        } else {
            addErrorMessage("Paramètres manquants: userId ou roleName");
        }
    }

    /**
     * Obtenir les rôles RoleDTO correspondant aux noms de rôles de l'utilisateur
     */
    public List<RoleDTO> getUserRolesDTOs(UserDTO user) {
        if (user == null || user.getRealmRoles() == null || user.getRealmRoles().isEmpty()) {
            return new ArrayList<>();
        }

        if (allRoles == null || allRoles.isEmpty()) {
            return new ArrayList<>();
        }

        return allRoles.stream()
                .filter(role -> user.getRealmRoles().contains(role.getName()))
                .collect(Collectors.toList());
    }

    /**
     * Réinitialiser le formulaire
     */
    public void resetForm() {
        newRole = RoleDTO.builder().build();
        editMode = false;
    }

    /**
     * Charger les realms disponibles depuis Keycloak
     */
    private void loadRealms() {
        try {
            availableRealms = realmServiceClient.getAllRealms();
            LOGGER.info("Realms chargés: " + availableRealms);
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des realms: " + e.getMessage());
            availableRealms = List.of("master", "lions-user-manager", "btpxpress", "unionflow");
        }
    }

    /**
     * Charger les clients disponibles pour le realm sélectionné
     */
    private void loadClients() {
        if (realmName == null || realmName.isEmpty()) {
            availableClients = new ArrayList<>();
            return;
        }

        try {
            availableClients = realmServiceClient.getRealmClients(realmName);
            LOGGER.info("Clients chargés pour " + realmName + ": " + availableClients.size());
        } catch (Exception e) {
            LOGGER.severe("Erreur lors du chargement des clients: " + e.getMessage());
            availableClients = new ArrayList<>();
        }
    }

    /**
     * Charger les rôles du realm spécifié.
     */
    public void loadRolesForUser(String realm) {
        if (realm != null && !realm.isEmpty()) {
            this.realmName = realm;
            loadRealmRoles();
        } else {
            loadRealmRoles();
        }
    }

    private void addSuccessMessage(String message) {
        FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_INFO, "Succès", message));
    }

    private void addErrorMessage(String message) {
        FacesContext.getCurrentInstance().addMessage(null,
                new FacesMessage(FacesMessage.SEVERITY_ERROR, "Erreur", message));
    }
}
