package dev.lions.unionflow.client.view;

import dev.lions.unionflow.server.api.dto.user.request.CreateUserRequest;
import dev.lions.unionflow.server.api.dto.user.request.UpdateUserRequest;
import dev.lions.unionflow.server.api.dto.user.response.UserResponse;
import dev.lions.unionflow.server.api.dto.base.PageResponse;
import dev.lions.unionflow.server.api.dto.common.PagedResponse;
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationResponse;
import dev.lions.unionflow.server.api.dto.organisation.response.OrganisationSummaryResponse;
import dev.lions.unionflow.client.service.AdminUserService;
import dev.lions.unionflow.client.service.OrganisationService;
import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Inject;
import jakarta.inject.Named;
import jakarta.annotation.PostConstruct;
import org.eclipse.microprofile.rest.client.inject.RestClient;
import java.io.Serializable;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import org.jboss.logging.Logger;

/**
 * Bean de gestion des utilisateurs Keycloak (liste, filtres, statistiques).
 * Appelle l'API Unionflow /api/admin/users (réservée SUPER_ADMIN).
 */
@Named("utilisateursBean")
@SessionScoped
public class UtilisateursBean implements Serializable {

    private static final long serialVersionUID = 1L;
    private static final Logger LOG = Logger.getLogger(UtilisateursBean.class);

    @Inject
    @RestClient
    private OrganisationService organisationService;

    @Inject
    @RestClient
    private AdminUserService adminUserService;

    private List<Utilisateur> tousLesUtilisateurs;
    private List<Utilisateur> utilisateursFiltres;
    private List<Utilisateur> utilisateursSelectionnes;
    private List<Organisation> organisationsDisponibles;

    private Utilisateur utilisateurSelectionne;
    private NouvelUtilisateur nouvelUtilisateur;
    private Filtres filtres;
    private StatistiquesUtilisateurs statistiques;

    @PostConstruct
    public void init() {
        initializeFiltres();
        initializeOrganisations();
        initializeUtilisateurs();
        initializeStatistiques();
        initializeNouvelUtilisateur();
        appliquerFiltres();
    }

    private void initializeFiltres() {
        filtres = new Filtres();
        utilisateursSelectionnes = new ArrayList<>();
    }

    private void initializeStatistiques() {
        statistiques = new StatistiquesUtilisateurs();
        statistiques.setTotalUtilisateurs(tousLesUtilisateurs != null ? tousLesUtilisateurs.size() : 0);
        statistiques.setUtilisateursConnectes(0);
        statistiques
                .setAdministrateurs(tousLesUtilisateurs != null
                        ? (int) tousLesUtilisateurs.stream()
                                .filter(u -> "ADMIN".equals(u.getRole()) || "SUPER_ADMIN".equals(u.getRole())).count()
                        : 0);
        statistiques.setUtilisateursDesactives(tousLesUtilisateurs != null
                ? (int) tousLesUtilisateurs.stream().filter(u -> "INACTIF".equals(u.getStatut())).count()
                : 0);
    }

    private void initializeOrganisations() {
        organisationsDisponibles = new ArrayList<>();
        try {
            PagedResponse<OrganisationSummaryResponse> response = organisationService.listerToutes(0, 1000);
            List<OrganisationSummaryResponse> associations = (response != null && response.getData() != null) ? response.getData()
                    : new ArrayList<>();
            for (OrganisationSummaryResponse assoc : associations) {
                Organisation org = new Organisation();
                org.setId(assoc.getId());
                org.setNom(assoc.getNom());
                organisationsDisponibles.add(org);
            }
        } catch (Exception e) {
            LOG.errorf(e, "Erreur lors du chargement des organisations");
        }
    }

    private void initializeUtilisateurs() {
        tousLesUtilisateurs = new ArrayList<>();
        try {
            PageResponse<UserResponse> result = adminUserService.lister(0, 1000, null);
            if (result != null && result.getContenu() != null) {
                for (UserResponse dto : result.getContenu()) {
                    Utilisateur u = mapToUtilisateur(dto);
                    tousLesUtilisateurs.add(u);
                }
            }
            LOG.infof("Utilisateurs chargés: %d", tousLesUtilisateurs.size());
        } catch (Exception e) {
            LOG.warnf(e, "Impossible de charger les utilisateurs (API admin): %s", e.getMessage());
        }
    }

    private Utilisateur mapToUtilisateur(UserResponse dto) {
        Utilisateur u = new Utilisateur();
        u.setId(dto.getId());
        u.setPrenom(dto.getPrenom());
        u.setNom(dto.getNom());
        u.setEmail(dto.getEmail());
        u.setRole(dto.getPrimaryRole());
        u.setStatut(Boolean.TRUE.equals(dto.getEnabled()) ? "ACTIF" : "INACTIF");
        u.setDateCreation(dto.getDateCreation());
        u.setDerniereConnexion(dto.getDerniereConnexion());
        return u;
    }

    private void initializeNouvelUtilisateur() {
        nouvelUtilisateur = new NouvelUtilisateur();
        nouvelUtilisateur.setRole("USER");
        nouvelUtilisateur.setEnvoyerEmail(true);
    }

    private void appliquerFiltres() {
        utilisateursFiltres = tousLesUtilisateurs.stream()
                .filter(this::appliquerFiltre)
                .collect(Collectors.toList());
    }

    private boolean appliquerFiltre(Utilisateur utilisateur) {
        if (filtres.getRecherche() != null && !filtres.getRecherche().trim().isEmpty()) {
            String recherche = filtres.getRecherche().toLowerCase();
            if (!utilisateur.getNomComplet().toLowerCase().contains(recherche) &&
                    !utilisateur.getEmail().toLowerCase().contains(recherche)) {
                return false;
            }
        }

        if (filtres.getRole() != null && !filtres.getRole().trim().isEmpty()) {
            if (!utilisateur.getRole().equals(filtres.getRole())) {
                return false;
            }
        }

        if (filtres.getStatut() != null && !filtres.getStatut().trim().isEmpty()) {
            if (!utilisateur.getStatut().equals(filtres.getStatut())) {
                return false;
            }
        }

        if (filtres.getOrganisation() != null && !filtres.getOrganisation().toString().trim().isEmpty()) {
            if (!utilisateur.getOrganisationId().equals(filtres.getOrganisation())) {
                return false;
            }
        }

        return true;
    }

    // Actions
    public void rechercher() {
        appliquerFiltres();
    }

    public void reinitialiserFiltres() {
        filtres = new Filtres();
        appliquerFiltres();
    }

    public void creerUtilisateur() {
        if (nouvelUtilisateur == null || nouvelUtilisateur.getEmail() == null
                || nouvelUtilisateur.getEmail().isBlank()) {
            LOG.warn("Création utilisateur: email obligatoire");
            return;
        }
        try {
            CreateUserRequest request = CreateUserRequest.builder()
                    .prenom(nouvelUtilisateur.getPrenom())
                    .nom(nouvelUtilisateur.getNom())
                    .email(nouvelUtilisateur.getEmail())
                    .username(nouvelUtilisateur.getEmail() != null ? nouvelUtilisateur.getEmail().trim().toLowerCase() : null)
                    .password(nouvelUtilisateur.getMotDePasse())
                    .enabled(true)
                    .emailVerified(false)
                    .realmRoles(nouvelUtilisateur.getRole() != null
                            ? Collections.singletonList(nouvelUtilisateur.getRole())
                            : Collections.singletonList("USER"))
                    .build();
            adminUserService.creer(request);
            LOG.infof("Utilisateur créé: %s", request.email());
            initializeUtilisateurs();
            initializeStatistiques();
            appliquerFiltres();
            initializeNouvelUtilisateur();
        } catch (Exception e) {
            LOG.errorf(e, "Erreur création utilisateur: %s", e.getMessage());
        }
    }

    public void activerUtilisateur(Utilisateur utilisateur) {
        if (utilisateur == null || utilisateur.getId() == null)
            return;
        try {
            UpdateUserRequest request = UpdateUserRequest.builder()
                    .enabled(true)
                    .build();
            adminUserService.mettreAJour(utilisateur.getId().toString(), request);
            LOG.infof("Utilisateur activé: %s", utilisateur.getEmail());
            initializeUtilisateurs();
            initializeStatistiques();
            appliquerFiltres();
        } catch (Exception e) {
            LOG.errorf(e, "Erreur activation utilisateur: %s", e.getMessage());
        }
    }

    public void desactiverUtilisateur(Utilisateur utilisateur) {
        if (utilisateur == null || utilisateur.getId() == null)
            return;
        try {
            UpdateUserRequest request = UpdateUserRequest.builder()
                    .enabled(false)
                    .build();
            adminUserService.mettreAJour(utilisateur.getId().toString(), request);
            LOG.infof("Utilisateur désactivé: %s", utilisateur.getEmail());
            initializeUtilisateurs();
            initializeStatistiques();
            appliquerFiltres();
        } catch (Exception e) {
            LOG.errorf(e, "Erreur désactivation utilisateur: %s", e.getMessage());
        }
    }

    public void exporterUtilisateurs() {
        // Export côté client à partir des données déjà chargées (utilisateursFiltres)
        LOG.info("Export utilisateurs (données courantes)");
    }

    // Getters et Setters
    public List<Utilisateur> getTousLesUtilisateurs() {
        return tousLesUtilisateurs;
    }

    public void setTousLesUtilisateurs(List<Utilisateur> tousLesUtilisateurs) {
        this.tousLesUtilisateurs = tousLesUtilisateurs;
    }

    public List<Utilisateur> getUtilisateursFiltres() {
        return utilisateursFiltres;
    }

    public void setUtilisateursFiltres(List<Utilisateur> utilisateursFiltres) {
        this.utilisateursFiltres = utilisateursFiltres;
    }

    public List<Utilisateur> getUtilisateursSelectionnes() {
        return utilisateursSelectionnes;
    }

    public void setUtilisateursSelectionnes(List<Utilisateur> utilisateursSelectionnes) {
        this.utilisateursSelectionnes = utilisateursSelectionnes;
    }

    public List<Organisation> getOrganisationsDisponibles() {
        return organisationsDisponibles;
    }

    public void setOrganisationsDisponibles(List<Organisation> organisationsDisponibles) {
        this.organisationsDisponibles = organisationsDisponibles;
    }

    public Utilisateur getUtilisateurSelectionne() {
        return utilisateurSelectionne;
    }

    public void setUtilisateurSelectionne(Utilisateur utilisateurSelectionne) {
        this.utilisateurSelectionne = utilisateurSelectionne;
    }

    public NouvelUtilisateur getNouvelUtilisateur() {
        return nouvelUtilisateur;
    }

    public void setNouvelUtilisateur(NouvelUtilisateur nouvelUtilisateur) {
        this.nouvelUtilisateur = nouvelUtilisateur;
    }

    public Filtres getFiltres() {
        return filtres;
    }

    public void setFiltres(Filtres filtres) {
        this.filtres = filtres;
    }

    public StatistiquesUtilisateurs getStatistiques() {
        return statistiques;
    }

    public void setStatistiques(StatistiquesUtilisateurs statistiques) {
        this.statistiques = statistiques;
    }

    // Classes internes
    public static class Utilisateur {
        private UUID id;
        private String nom;
        private String prenom;
        private String email;
        private String telephone;
        private String role;
        private String statut;
        private UUID organisationId;
        private LocalDateTime dateCreation;
        private LocalDateTime derniereConnexion;

        // Getters et setters
        public UUID getId() {
            return id;
        }

        public void setId(UUID id) {
            this.id = id;
        }

        public String getNom() {
            return nom;
        }

        public void setNom(String nom) {
            this.nom = nom;
        }

        public String getPrenom() {
            return prenom;
        }

        public void setPrenom(String prenom) {
            this.prenom = prenom;
        }

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public String getTelephone() {
            return telephone;
        }

        public void setTelephone(String telephone) {
            this.telephone = telephone;
        }

        public String getRole() {
            return role;
        }

        public void setRole(String role) {
            this.role = role;
        }

        public String getStatut() {
            return statut;
        }

        public void setStatut(String statut) {
            this.statut = statut;
        }

        public UUID getOrganisationId() {
            return organisationId;
        }

        public void setOrganisationId(UUID organisationId) {
            this.organisationId = organisationId;
        }

        public LocalDateTime getDateCreation() {
            return dateCreation;
        }

        public void setDateCreation(LocalDateTime dateCreation) {
            this.dateCreation = dateCreation;
        }

        public LocalDateTime getDerniereConnexion() {
            return derniereConnexion;
        }

        public void setDerniereConnexion(LocalDateTime derniereConnexion) {
            this.derniereConnexion = derniereConnexion;
        }

        // Propriétés dérivées
        public String getNomComplet() {
            if (prenom != null && nom != null)
                return prenom + " " + nom;
            if (prenom != null)
                return prenom;
            if (nom != null)
                return nom;
            return email != null ? email : "—";
        }

        public String getRoleLibelle() {
            return switch (role) {
                case "USER" -> "Utilisateur";
                case "GESTIONNAIRE" -> "Gestionnaire";
                case "ADMIN" -> "Administrateur";
                case "SUPER_ADMIN" -> "Super Admin";
                default -> role;
            };
        }

        public String getRoleSeverity() {
            return switch (role) {
                case "USER" -> "info";
                case "GESTIONNAIRE" -> "primary";
                case "ADMIN" -> "warning";
                case "SUPER_ADMIN" -> "danger";
                default -> "secondary";
            };
        }

        public String getStatutLibelle() {
            return switch (statut) {
                case "ACTIF" -> "Actif";
                case "INACTIF" -> "Inactif";
                case "SUSPENDU" -> "Suspendu";
                case "ATTENTE" -> "En attente";
                default -> statut;
            };
        }

        public String getStatutSeverity() {
            return switch (statut) {
                case "ACTIF" -> "success";
                case "INACTIF" -> "secondary";
                case "SUSPENDU" -> "danger";
                case "ATTENTE" -> "warning";
                default -> "secondary";
            };
        }

        public String getOrganisationNom() {
            // Simulation - en réalité, on ferait un lookup dans la base
            if (organisationId == null)
                return "Non définie";
            String orgIdStr = organisationId.toString();
            if (orgIdStr.contains("000000000100"))
                return "Direction Générale";
            if (orgIdStr.contains("000000000200"))
                return "Services Financiers";
            if (orgIdStr.contains("000000000300"))
                return "Ressources Humaines";
            if (orgIdStr.contains("000000000400"))
                return "Communication";
            return "Non définie";
        }

        public String getDateCreationFormatee() {
            if (dateCreation == null)
                return "";
            return dateCreation.format(DateTimeFormatter.ofPattern("dd/MM/yyyy"));
        }

        public String getDerniereConnexionFormatee() {
            if (derniereConnexion == null)
                return "Jamais";
            return derniereConnexion.format(DateTimeFormatter.ofPattern("dd/MM/yyyy HH:mm"));
        }

        public String getDerniereConnexionRelative() {
            if (derniereConnexion == null)
                return "Jamais connecté";
            long jours = ChronoUnit.DAYS.between(derniereConnexion, LocalDateTime.now());
            if (jours == 0)
                return "Aujourd'hui";
            if (jours == 1)
                return "Hier";
            if (jours < 7)
                return "Il y a " + jours + " jours";
            if (jours < 30)
                return "Il y a " + (jours / 7) + " semaine(s)";
            return "Il y a " + (jours / 30) + " mois";
        }
    }

    public static class NouvelUtilisateur {
        private String nom;
        private String prenom;
        private String email;
        private String telephone;
        private String role;
        private UUID organisationId;
        private String motDePasse;
        private boolean envoyerEmail;

        // Getters et setters
        public String getNom() {
            return nom;
        }

        public void setNom(String nom) {
            this.nom = nom;
        }

        public String getPrenom() {
            return prenom;
        }

        public void setPrenom(String prenom) {
            this.prenom = prenom;
        }

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public String getTelephone() {
            return telephone;
        }

        public void setTelephone(String telephone) {
            this.telephone = telephone;
        }

        public String getRole() {
            return role;
        }

        public void setRole(String role) {
            this.role = role;
        }

        public UUID getOrganisationId() {
            return organisationId;
        }

        public void setOrganisationId(UUID organisationId) {
            this.organisationId = organisationId;
        }

        public String getMotDePasse() {
            return motDePasse;
        }

        public void setMotDePasse(String motDePasse) {
            this.motDePasse = motDePasse;
        }

        public boolean isEnvoyerEmail() {
            return envoyerEmail;
        }

        public void setEnvoyerEmail(boolean envoyerEmail) {
            this.envoyerEmail = envoyerEmail;
        }
    }

    public static class Filtres {
        private String recherche;
        private String role;
        private String statut;
        private String connexion;
        private UUID organisation;

        // Getters et setters
        public String getRecherche() {
            return recherche;
        }

        public void setRecherche(String recherche) {
            this.recherche = recherche;
        }

        public String getRole() {
            return role;
        }

        public void setRole(String role) {
            this.role = role;
        }

        public String getStatut() {
            return statut;
        }

        public void setStatut(String statut) {
            this.statut = statut;
        }

        public String getConnexion() {
            return connexion;
        }

        public void setConnexion(String connexion) {
            this.connexion = connexion;
        }

        public UUID getOrganisation() {
            return organisation;
        }

        public void setOrganisation(UUID organisation) {
            this.organisation = organisation;
        }
    }

    public static class StatistiquesUtilisateurs {
        private int totalUtilisateurs;
        private int utilisateursConnectes;
        private int administrateurs;
        private int utilisateursDesactives;

        // Getters et setters
        public int getTotalUtilisateurs() {
            return totalUtilisateurs;
        }

        public void setTotalUtilisateurs(int totalUtilisateurs) {
            this.totalUtilisateurs = totalUtilisateurs;
        }

        public int getUtilisateursConnectes() {
            return utilisateursConnectes;
        }

        public void setUtilisateursConnectes(int utilisateursConnectes) {
            this.utilisateursConnectes = utilisateursConnectes;
        }

        public int getAdministrateurs() {
            return administrateurs;
        }

        public void setAdministrateurs(int administrateurs) {
            this.administrateurs = administrateurs;
        }

        public int getUtilisateursDesactives() {
            return utilisateursDesactives;
        }

        public void setUtilisateursDesactives(int utilisateursDesactives) {
            this.utilisateursDesactives = utilisateursDesactives;
        }
    }

    public static class Organisation {
        private UUID id;
        private String nom;

        // Getters et setters
        public UUID getId() {
            return id;
        }

        public void setId(UUID id) {
            this.id = id;
        }

        public String getNom() {
            return nom;
        }

        public void setNom(String nom) {
            this.nom = nom;
        }
    }
}
