package dev.lions.unionflow.server.service;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import dev.lions.unionflow.server.api.dto.config.request.UpdateConfigurationRequest;
import dev.lions.unionflow.server.api.dto.config.response.ConfigurationResponse;
import dev.lions.unionflow.server.entity.Configuration;
import dev.lions.unionflow.server.repository.ConfigurationRepository;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.transaction.Transactional;
import jakarta.ws.rs.NotFoundException;
import org.jboss.logging.Logger;

import java.util.*;
import java.util.stream.Collectors;

/**
 * Service métier pour la gestion de la configuration système
 * 
 * @author UnionFlow Team
 * @version 1.0
 */
@ApplicationScoped
public class ConfigurationService {

    private static final Logger LOG = Logger.getLogger(ConfigurationService.class);

    @Inject
    ConfigurationRepository configurationRepository;

    private final ObjectMapper objectMapper = new ObjectMapper();

    public List<ConfigurationResponse> listerConfigurations() {
        LOG.info("Récupération de toutes les configurations");
        List<Configuration> configurations = configurationRepository.findAllActives();
        return configurations.stream()
                .map(this::toDTO)
                .collect(Collectors.toList());
    }

    public ConfigurationResponse obtenirConfiguration(String cle) {
        LOG.infof("Récupération de la configuration %s", cle);
        Optional<Configuration> config = configurationRepository.findByCle(cle);
        if (config.isEmpty() || !config.get().getActif()) {
            throw new NotFoundException("Configuration non trouvée avec la clé: " + cle);
        }
        return toDTO(config.get());
    }

    @Transactional
    public ConfigurationResponse mettreAJourConfiguration(String cle, UpdateConfigurationRequest request) {
        LOG.infof("Mise à jour de la configuration %s", cle);

        Optional<Configuration> configOpt = configurationRepository.findByCle(cle);
        Configuration configuration;

        if (configOpt.isPresent()) {
            configuration = configOpt.get();
            if (!configuration.getModifiable()) {
                throw new IllegalArgumentException("La configuration " + cle + " n'est pas modifiable");
            }
            // Mettre à jour les champs
            configuration.setValeur(request.valeur());
            configuration.setType(request.type());
            configuration.setDescription(request.description());
            if (request.metadonnees() != null) {
                try {
                    configuration.setMetadonnees(objectMapper.writeValueAsString(request.metadonnees()));
                } catch (Exception e) {
                    LOG.warnf("Erreur lors de la sérialisation des métadonnées: %s", e.getMessage());
                }
            }
            configurationRepository.update(configuration);
        } else {
            // Créer une nouvelle configuration
            configuration = toEntity(request);
            configuration.setCle(cle);
            configurationRepository.persist(configuration);
        }

        LOG.infof("Configuration mise à jour avec succès: %s", cle);
        return toDTO(configuration);
    }

    // Mappers Entity <-> DTO (DRY/WOU)
    private ConfigurationResponse toDTO(Configuration configuration) {
        if (configuration == null)
            return null;
        Map<String, Object> metadonnees = null;
        if (configuration.getMetadonnees() != null && !configuration.getMetadonnees().isEmpty()) {
            try {
                metadonnees = objectMapper.readValue(configuration.getMetadonnees(),
                        new TypeReference<Map<String, Object>>() {
                        });
            } catch (Exception e) {
                LOG.warnf("Erreur lors de la désérialisation des métadonnées: %s", e.getMessage());
            }
        }
        ConfigurationResponse response = new ConfigurationResponse();
        response.setId(configuration.getId());
        response.setCle(configuration.getCle());
        response.setValeur(configuration.getValeur());
        response.setType(configuration.getType());
        response.setCategorie(configuration.getCategorie());
        response.setDescription(configuration.getDescription());
        response.setModifiable(configuration.getModifiable());
        response.setVisible(configuration.getVisible());
        response.setMetadonnees(metadonnees);
        return response;
    }

    private Configuration toEntity(UpdateConfigurationRequest dto) {
        if (dto == null)
            return null;
        Configuration configuration = new Configuration();
        configuration.setCle(dto.cle());
        configuration.setValeur(dto.valeur());
        configuration.setType(dto.type());
        configuration.setCategorie(dto.categorie());
        configuration.setDescription(dto.description());
        configuration.setModifiable(dto.modifiable());
        configuration.setVisible(dto.visible());
        if (dto.metadonnees() != null) {
            try {
                configuration.setMetadonnees(objectMapper.writeValueAsString(dto.metadonnees()));
            } catch (Exception e) {
                LOG.warnf("Erreur lors de la sérialisation des métadonnées: %s", e.getMessage());
            }
        }
        return configuration;
    }
}
