package dev.lions.user.manager.mapper;

import dev.lions.user.manager.dto.user.UserDTO;
import dev.lions.user.manager.enums.user.StatutUser;
import org.keycloak.representations.idm.UserRepresentation;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * Mapper pour convertir UserRepresentation (Keycloak) -> UserDTO
 * Utilisé pour transformer les objets de l'API Keycloak vers nos DTOs
 */
public class UserMapper {

    private UserMapper() {
        // Classe utilitaire
    }

    /**
     * Convertit UserRepresentation vers UserDTO
     * @param userRep UserRepresentation de Keycloak
     * @param realmName nom du realm
     * @return UserDTO
     */
    public static UserDTO toDTO(UserRepresentation userRep, String realmName) {
        if (userRep == null) {
            return null;
        }

        return UserDTO.builder()
            .id(userRep.getId())
            .username(userRep.getUsername())
            .email(userRep.getEmail())
            .emailVerified(userRep.isEmailVerified())
            .prenom(userRep.getFirstName())
            .nom(userRep.getLastName())
            .statut(StatutUser.fromEnabled(userRep.isEnabled()))
            .enabled(userRep.isEnabled())
            .realmName(realmName)
            .attributes(userRep.getAttributes())
            .requiredActions(userRep.getRequiredActions())
            .dateCreation(convertTimestamp(userRep.getCreatedTimestamp()))
            .telephone(getAttributeValue(userRep, "phone_number"))
            .organisation(getAttributeValue(userRep, "organization"))
            .departement(getAttributeValue(userRep, "department"))
            .fonction(getAttributeValue(userRep, "job_title"))
            .pays(getAttributeValue(userRep, "country"))
            .ville(getAttributeValue(userRep, "city"))
            .langue(getAttributeValue(userRep, "locale"))
            .timezone(getAttributeValue(userRep, "timezone"))
            .build();
    }

    /**
     * Convertit UserDTO vers UserRepresentation
     * @param userDTO UserDTO
     * @return UserRepresentation
     */
    public static UserRepresentation toRepresentation(UserDTO userDTO) {
        if (userDTO == null) {
            return null;
        }

        UserRepresentation userRep = new UserRepresentation();
        userRep.setId(userDTO.getId());
        userRep.setUsername(userDTO.getUsername());
        userRep.setEmail(userDTO.getEmail());
        userRep.setEmailVerified(userDTO.getEmailVerified());
        userRep.setFirstName(userDTO.getPrenom());
        userRep.setLastName(userDTO.getNom());
        userRep.setEnabled(userDTO.getEnabled() != null ? userDTO.getEnabled() : true);

        // Attributs personnalisés
        Map<String, List<String>> attributes = new HashMap<>();

        if (userDTO.getTelephone() != null) {
            attributes.put("phone_number", List.of(userDTO.getTelephone()));
        }
        if (userDTO.getOrganisation() != null) {
            attributes.put("organization", List.of(userDTO.getOrganisation()));
        }
        if (userDTO.getDepartement() != null) {
            attributes.put("department", List.of(userDTO.getDepartement()));
        }
        if (userDTO.getFonction() != null) {
            attributes.put("job_title", List.of(userDTO.getFonction()));
        }
        if (userDTO.getPays() != null) {
            attributes.put("country", List.of(userDTO.getPays()));
        }
        if (userDTO.getVille() != null) {
            attributes.put("city", List.of(userDTO.getVille()));
        }
        if (userDTO.getLangue() != null) {
            attributes.put("locale", List.of(userDTO.getLangue()));
        }
        if (userDTO.getTimezone() != null) {
            attributes.put("timezone", List.of(userDTO.getTimezone()));
        }

        // Ajouter les attributs existants du DTO
        if (userDTO.getAttributes() != null) {
            attributes.putAll(userDTO.getAttributes());
        }

        userRep.setAttributes(attributes);

        // Actions requises
        if (userDTO.getRequiredActions() != null) {
            userRep.setRequiredActions(userDTO.getRequiredActions());
        }

        return userRep;
    }

    /**
     * Convertit une liste de UserRepresentation vers UserDTO
     * @param userReps liste de UserRepresentation
     * @param realmName nom du realm
     * @return liste de UserDTO
     */
    public static List<UserDTO> toDTOList(List<UserRepresentation> userReps, String realmName) {
        if (userReps == null) {
            return new ArrayList<>();
        }

        return userReps.stream()
            .map(userRep -> toDTO(userRep, realmName))
            .collect(Collectors.toList());
    }

    /**
     * Récupère la valeur d'un attribut Keycloak
     * @param userRep UserRepresentation
     * @param attributeName nom de l'attribut
     * @return valeur de l'attribut ou null
     */
    private static String getAttributeValue(UserRepresentation userRep, String attributeName) {
        if (userRep.getAttributes() == null) {
            return null;
        }

        List<String> values = userRep.getAttributes().get(attributeName);
        if (values == null || values.isEmpty()) {
            return null;
        }

        return values.get(0);
    }

    /**
     * Convertit un timestamp (millisecondes) vers LocalDateTime
     * @param timestamp timestamp en millisecondes
     * @return LocalDateTime ou null
     */
    private static LocalDateTime convertTimestamp(Long timestamp) {
        if (timestamp == null) {
            return null;
        }

        return LocalDateTime.ofInstant(
            Instant.ofEpochMilli(timestamp),
            ZoneId.systemDefault()
        );
    }
}
