package com.banesco.common.infraestructure.repository;

import com.banesco.common.domain.model.BackResponse;
import com.banesco.common.domain.dto.bian.device.JsonHelper;
import com.banesco.common.domain.dto.bian.device.StringHelper;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

public class MessageRepository {

    private static final Logger logger = Logger.getLogger(MessageRepository.class.getName());

    /**
     * Respuesta de error por defecto que se utiliza cuando no se encuentra un
     * error específico.
     */

    /**
     * Mapa que almacena múltiples mapas de códigos de error, donde la clave
     * principal es el nombre del archivo de mensajes.
     */
    public final Map<String, Map<String, BackResponse>> mapErrorsMultiple = new HashMap<>();

    /**
     * Carga los mensajes de error desde un InputStream y los almacena en un
     * mapa.
     *
     * @param inputStream    El InputStream que contiene los datos JSON de los
     *                       mensajes de error.
     * @param messageFileKey La clave del archivo de mensajes, utilizada para
     *                       almacenar el mapa en mapErrorsMultiple.
     * @return Un mapa que contiene los códigos de error como claves y los
     * objetos BackResponse como valores.
     * @throws IOException Si ocurre un error de entrada/salida al leer el
     *                     InputStream.
     */
    private Map<String, BackResponse> loadFile(InputStream inputStream, String messageFileKey) throws IOException {
        Map<String, BackResponse> mapStatusCodes = new HashMap<>();
        Arrays.stream(JsonHelper.MAPPER.readValue(inputStream, BackResponse[].class)).forEach(o -> {
            mapStatusCodes.put(o.getBackendCode(), o);
        });
        mapErrorsMultiple.put(messageFileKey, mapStatusCodes);
        return mapStatusCodes;
    }

    /**
     * Carga los mensajes de error desde una cadena JSON y los almacena en un
     * mapa.
     *
     * @param messageFileKey La clave del archivo de mensajes, utilizada para
     *                       almacenar el mapa en mapErrorsMultiple.
     * @param jsonString     La cadena JSON que contiene los datos de los mensajes
     *                       de error.
     * @throws IOException Si ocurre un error al procesar la cadena JSON.
     */
    public void loadMessagesFromString(String messageFileKey, String jsonString) throws IOException {
        Map<String, BackResponse> mapStatusCodes = new HashMap<>();
        Arrays.stream(JsonHelper.MAPPER.readValue(jsonString, BackResponse[].class)).forEach(o -> {
            mapStatusCodes.put(o.getBackendCode(), o);
        });
        mapErrorsMultiple.put(messageFileKey, mapStatusCodes);
    }

    /**
     * Obtiene el mapa de códigos de error para un archivo de respuesta
     * específico.
     *
     * @param responseFile El nombre del archivo de respuesta para el cual se
     *                     desea obtener el mapa de errores.
     * @return Un mapa que contiene los códigos de error como claves y los
     * objetos BackResponse como valores, o null si no se encuentra el mapa.
     */
    public Map<String, BackResponse> getErrorMap(String responseFile, boolean insideProperties) {
        Map<String, BackResponse> errorMap = mapErrorsMultiple.get(responseFile);
        if (insideProperties || (errorMap != null && !errorMap.isEmpty())) {
            return errorMap;
        }

        String fileName = (StringHelper.isNumeric(responseFile) ? "vb".concat(responseFile) : responseFile).concat(".json");

        try {
            try {
                // Intenta cargar el archivo desde el directorio /config/.
                return loadFile(new FileInputStream("/config/".concat(fileName)), responseFile);
            } catch (IOException e) {
                // Si no se encuentra el archivo en /config/, intenta cargarlo desde el classpath.
                logger.log(Level.WARNING, "Path /config/" + fileName + " not found. Loading local from errors-mapping/" + fileName);
                ClassLoader classLoader = getClass().getClassLoader();
                InputStream inputStream = classLoader.getResourceAsStream("errors-mapping/" + fileName);
                if (inputStream == null) {
                    // Si no se encuentra el archivo en el classpath, registra un error y devuelve null.
                    logger.log(Level.SEVERE, "Resource errors-mapping/" + fileName + " not found.");
                    return null;
                }
                return loadFile(inputStream, responseFile);
            }
        } catch (IOException e) {
            // Si ocurre un error al cargar el archivo desde cualquier ubicación, registra un error y devuelve null.
            logger.log(Level.SEVERE, "Error getting Service Messages to /config/".concat(fileName) + ": " + e.getMessage());

            return null;
        }
    }
}
