package infrastructure.mapper;

import com.banesco.common.domain.model.redis.postgres.customer_product.CustomerAccountConfiguration;
import com.banesco.common.domain.model.redis.postgres.customer_product.CustomerAccountJsonConfig;
import com.banesco.common.domain.model.redis.postgres.customer_product.CustomerAccountPostgresConfig;

import domain.entity.AppConfiguration;
import domain.entity.ConfigItem;
import domain.model.Configuration;

import java.util.Map;
import java.util.stream.Collectors;

/**
 * Mapeador estático para convertir entidades de la App (JPA)
 * a DTOs de "commons" (para Redis).
 */
public class PostgresMapper {

    /**
     * Constructor privado para evitar que esta clase de utilidad sea instanciada.
     */
    private PostgresMapper() {}

    public static CustomerAccountPostgresConfig mapToCommon(AppConfiguration appEntity) {
        if (appEntity == null) {
            return null;
        }

        var commonDto = new CustomerAccountPostgresConfig();

        commonDto.setAppId(appEntity.getAppId());
        commonDto.setAppName(appEntity.getAppName());
        commonDto.setApiName(appEntity.getApiName());
        commonDto.setType(appEntity.getType());
        commonDto.setEvent(appEntity.getEvent());
        commonDto.setEncryptionData(appEntity.isEncryptionData());

        commonDto.setConfiguration(mapConfigurationToCommon(appEntity.getConfiguration()));

        return commonDto;
    }

    private static CustomerAccountConfiguration mapConfigurationToCommon(Configuration appConfig) {
        if (appConfig == null) {
            return null;
        }

        var commonConfigDto = new CustomerAccountConfiguration();

        // Mapea los aliases (son Map<String, String>, se copian directo)
        commonConfigDto.setValidationRules(appConfig.getValidationRules());
        commonConfigDto.setAliases(appConfig.getAliases());

        // Mapea el mapa de configuración, convirtiendo cada ConfigItem (llama al Nivel 3)
        if (appConfig.getConfiguration() != null) {
            var commonConfigMap =  appConfig.getConfiguration().entrySet().stream()
                            .collect(Collectors.toMap(
                                    Map.Entry::getKey,
                                    entry -> mapConfigItemToCommon(entry.getValue()) // El valor (ConfigItem) se mapea
                            ));
            commonConfigDto.setConfiguration(commonConfigMap);
        }

        return commonConfigDto;
    }

    /**
     * Nivel 3: Mapea un ConfigItem (App) a su DTO CustomerAccountJsonConfig (Commons).
     * Como tienen los mismos campos, es una copia directa.
     */
    private static CustomerAccountJsonConfig mapConfigItemToCommon(ConfigItem appItem) {
        if (appItem == null) {
            return null;
        }

        var commonItemDto = new CustomerAccountJsonConfig();

        commonItemDto.setCacheable(appItem.isCacheable());
        commonItemDto.setBankCode(appItem.getBankCode());
        commonItemDto.setCurrencyCode(appItem.getCurrencyCode());
        commonItemDto.setStatus(appItem.getStatus());
        commonItemDto.setStatusMe(appItem.getStatusMe());
        commonItemDto.setProductCv(appItem.getProductCv());
        commonItemDto.setProduct(appItem.getProduct());
        commonItemDto.setChannel(appItem.getChannel());
        commonItemDto.setService(appItem.getService());
        commonItemDto.setOperator(appItem.getOperator());
        commonItemDto.setPhone(appItem.getPhone());
        commonItemDto.setAffiliationStatus(appItem.getAffiliationStatus());
        commonItemDto.setCounterpartyAccount(appItem.getCounterpartyAccount());
        commonItemDto.setHolder(appItem.getHolder());
        commonItemDto.setCodProduct(appItem.getCodProduct());
        commonItemDto.setStatusOperation(appItem.getStatusOperation());
        commonItemDto.setStatusRestriction(appItem.getStatusRestriction());
        commonItemDto.setStatusOperationRestriction(appItem.getStatusOperationRestriction());

        return commonItemDto;
    }

    /**
     * Nivel  (Inverso): Mapea el DTO de "commons" a la entidad AppConfiguration (App).
     * NOTA: ¡Esto requiere que tu entidad AppConfiguration tenga setters!
     */
    public static AppConfiguration mapToApp(CustomerAccountPostgresConfig commonDto) {
        if (commonDto == null) {
            return null;
        }

        var appEntity = new AppConfiguration();

        // Asumiendo que existen setters... (ver nota abajo)
        appEntity.setAppId(commonDto.getAppId());
        appEntity.setAppName(commonDto.getAppName());
        appEntity.setApiName(commonDto.getApiName());
        appEntity.setType(commonDto.getType());
        appEntity.setEvent(commonDto.getEvent());
        appEntity.setEncryptionData(commonDto.isEncryptionData());

        // Mapeo inverso de objetos anidados (Nivel 2)
        appEntity.setConfiguration(mapConfigurationToApp(commonDto.getConfiguration()));

        return appEntity;
    }

    /**
     * Nivel 2 (Inverso): Mapea el DTO de Configuración (Commons) a la clase de Modelo (App).
     */
    private static Configuration mapConfigurationToApp(CustomerAccountConfiguration commonConfigDto) {
        if (commonConfigDto == null) {
            return null;
        }

        var appConfig = new Configuration();

        appConfig.setValidationRules(commonConfigDto.getValidationRules());
        appConfig.setAliases(commonConfigDto.getAliases());

        // Mapea el mapa de configuración (Nivel 3)
        if (commonConfigDto.getConfiguration() != null) {
            var appConfigMap = commonConfigDto.getConfiguration().entrySet().stream()
                    .collect(Collectors.toMap(
                            Map.Entry::getKey,
                            entry -> mapConfigItemToApp(entry.getValue())
                    ));
            appConfig.setConfiguration(appConfigMap);
        }

        return appConfig;
    }

    /**
     * Nivel 3 (Inverso): Mapea el DTO de ConfigItem (Commons) a la Entidad (App).
     */
    private static ConfigItem mapConfigItemToApp(CustomerAccountJsonConfig commonItemDto) {
        if (commonItemDto == null) {
            return null;
        }

        var appItem = new ConfigItem();

        // Mapeo 1:1
        appItem.setCacheable(commonItemDto.isCacheable());
        appItem.setBankCode(commonItemDto.getBankCode());
        appItem.setCurrencyCode(commonItemDto.getCurrencyCode());
        appItem.setStatus(commonItemDto.getStatus());
        appItem.setStatusMe(commonItemDto.getStatusMe());
        appItem.setProductCv(commonItemDto.getProductCv());
        appItem.setProduct(commonItemDto.getProduct());
        appItem.setChannel(commonItemDto.getChannel());
        appItem.setService(commonItemDto.getService());
        appItem.setOperator(commonItemDto.getOperator());
        appItem.setPhone(commonItemDto.getPhone());
        appItem.setAffiliationStatus(commonItemDto.getAffiliationStatus());
        appItem.setCounterpartyAccount(commonItemDto.getCounterpartyAccount());
        appItem.setHolder(commonItemDto.getHolder());
        appItem.setCodProduct(commonItemDto.getCodProduct());
        appItem.setStatusOperation(commonItemDto.getStatusOperation());
        appItem.setStatusRestriction(commonItemDto.getStatusRestriction());
        appItem.setStatusOperationRestriction(commonItemDto.getStatusOperationRestriction());

        return appItem;
    }

}