package com.banesco.common.application.helper;

import com.banesco.common.domain.exception.InternalServerException;
import com.banesco.common.domain.model.ErrorMapping;
import com.banesco.common.infrastructure.config.MessagesConfig;
import com.banesco.common.domain.exception.BaseApiException;
import com.banesco.common.domain.model.ApiResponse;
import com.banesco.common.domain.model.StatusResponse;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import io.quarkus.runtime.annotations.RegisterForReflection;
import lombok.extern.slf4j.Slf4j;
import jakarta.ws.rs.core.Response;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import java.io.InputStream;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Slf4j
@ApplicationScoped
@RegisterForReflection
public class MessageResponseHelper {

    private final MessagesConfig messagesConfig;
    private final Map<String, ErrorMapping> errorMappings;
    private static final String ERROR_DEFAULT = "default";
    private static final String SUCCESS_DEFAULT = "200";
    private static final String ERROR_FILE_PATH = "errors-mapping/errors.json";
    private final ObjectMapper objectMapper;

    @Inject
    public MessageResponseHelper(
        ObjectMapper objectMapper,
        MessagesConfig messagesConfig
    ) {
        this.objectMapper = objectMapper;
        this.messagesConfig = messagesConfig;
        this.errorMappings = initializeErrorMappings();
    }

    // Ya no es una clase interna, ahora usa la clase del dominio
    // Solo necesitas mantener la referencia al tipo
    // Si ErrorMapping está en otro paquete, asegúrate de importarlo

    public Response handleException(BaseApiException exception) {
        return buildErrorResponse(exception);
    }

    public Response handleGenericException(Exception exception) {
        log.error("Error interno no controlado: {}", exception.getMessage(), exception);
        return buildErrorResponse(new InternalServerException("500", null));
    }

    public StatusResponse createSuccessResponse(String code) {
        ErrorMapping successMapping = getError(code);

        return StatusResponse.builder()
                .statusCode(successMapping.getStatusCode())
                .message(successMapping.getDescription())
                .build();
    }

    public StatusResponse createErrorResponse(
            ErrorMapping mapping,
            String fieldPath
    ) {
        String message = mapping.getDescription();

        if (fieldPath != null && message != null && message.contains("%s")) {
            message = String.format(message, fieldPath);
        }

        return StatusResponse.builder()
                .statusCode(mapping.getStatusCode())
                .message(message)
                .build();
    }

    public <T> ApiResponse<T> buildServiceUnavailableResponse() {
        return new ApiResponse<>(null, createSuccessResponse("503"));
    }

    private ErrorMapping getError(String errorCode) {
        return errorMappings.getOrDefault(
                errorCode, errorMappings.getOrDefault(ERROR_DEFAULT, createDefaultMapping())
        );
    }

    private Response buildErrorResponse(BaseApiException exception) {
        ErrorMapping mapping = errorMappings.getOrDefault(
                exception.getErrorCode(),
                errorMappings.getOrDefault(ERROR_DEFAULT, createDefaultMapping())
        );
        StatusResponse status = createErrorResponse(
                mapping, exception.getFieldPath()
        );

        log.error(
                "[{}] Message {} -> {}",
                exception.getExceptionType(),
                exception.getErrorCode(),
                status.getMessage()
        );

        return Response.status(mapping.getHttpCode())
                .entity(new ApiResponse<>(null, status))
                .build();
    }

    private Map<String, ErrorMapping> initializeErrorMappings() {
        try {
            String json;

            if (isReadingFromProps()) {
                json = messagesConfig.getErrorMessagesJson();
                log.info("Cargando mensajes de errores desde properties");
            } else {
                json = loadFromJsonFile();
                log.info("Cargando mensajes de errores desde archivo JSON");
            }

            if (json == null || json.isEmpty()) {
                log.warn("No se encontró JSON de errores");
                return createDefaultMappings();
            }

            List<ErrorMapping> mappings = objectMapper.readValue(json, new TypeReference<List<ErrorMapping>>() {});
            Map<String, ErrorMapping> result = new ConcurrentHashMap<>();

            for (ErrorMapping mapping : mappings) {
                if (mapping.getBackendCode() != null && !mapping.getBackendCode().trim().isEmpty()) {
                    if (result.containsKey(mapping.getBackendCode())) {
                        log.warn("Clave duplicada encontrada en mappings de errores: {}", mapping.getBackendCode());
                    } else {
                        result.put(mapping.getBackendCode(), mapping);
                    }
                } else {
                    log.warn("Ignorando mapping sin backendCode válido: {}", mapping.getDescription());
                }
            }

            log.info("Mappings de errores cargados exitosamente, total válidos: {}", result.size());
            return result;
        } catch (Exception e) {
            log.error("Error cargando mappings de errores: {}", e.getMessage());
            return createDefaultMappings();
        }
    }

    private String loadFromJsonFile() {
        try (InputStream is = MessageResponseHelper.class.getClassLoader().getResourceAsStream(ERROR_FILE_PATH)) {
            if (is == null) {
                log.warn("No se encontró el archivo de errores: {}", ERROR_FILE_PATH);
                return "";
            }
            return new String(is.readAllBytes());
        } catch (Exception e) {
            log.error("Error leyendo archivo de errores: {}", e.getMessage());
            return "";
        }
    }

    private Map<String, ErrorMapping> createDefaultMappings() {
        Map<String, ErrorMapping> defaults = new ConcurrentHashMap<>();
        defaults.put(ERROR_DEFAULT, createDefaultMapping());
        defaults.put(SUCCESS_DEFAULT, createSuccessMapping());
        return defaults;
    }

    private ErrorMapping createDefaultMapping() {
        ErrorMapping mapping = new ErrorMapping();
        mapping.setBackendCode(ERROR_DEFAULT);
        mapping.setHttpCode(500);
        mapping.setStatusCode("500");
        mapping.setDescription("Error interno del servidor");
        return mapping;
    }

    private ErrorMapping createSuccessMapping() {
        ErrorMapping mapping = new ErrorMapping();
        mapping.setBackendCode(SUCCESS_DEFAULT);
        mapping.setHttpCode(200);
        mapping.setStatusCode("000");
        mapping.setDescription("Operación exitosa");
        return mapping;
    }

    public boolean isReadingFromProps() {
        return messagesConfig.isReadFromProps();
    }
}