package infrastructure.exception;

import application.exception.GatewayServiceException;
import com.banesco.common.application.exception.BanBackendException;
import domain.dto.response.CustomerResponse;
import domain.model.ErrorCode;
import infrastructure.context.TraceIdContext;
import infrastructure.service.StatusDescriptionResolver;
import jakarta.inject.Inject;
import jakarta.ws.rs.BadRequestException;
import jakarta.ws.rs.NotAllowedException;
import jakarta.ws.rs.NotFoundException;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.ext.ExceptionMapper;
import jakarta.ws.rs.ext.Provider;
import lombok.extern.slf4j.Slf4j;

@Slf4j
@Provider
public class GlobalExceptionHandler implements ExceptionMapper<Throwable> {

    @Inject
    TraceIdContext traceIdContext;

    @Inject
    StatusDescriptionResolver statusDescriptionResolver;

    @Override
    public Response toResponse(Throwable exception) {
        final var requestId = traceIdContext.getTraceId();
        ErrorCode resolvedCode;

        log.info("[ERROR: {}] Error de backend no manejado que llego al GlobalExceptionHandler", requestId, exception);

        var exceptionClassName = exception.getClass().getName();

        if (exception instanceof BanBackendException bbe) {
            resolvedCode = statusDescriptionResolver.getCode(bbe.getBackendCode());
            if (resolvedCode == null) {
                resolvedCode = statusDescriptionResolver.getCode("500");
            }
        } else if (exceptionClassName.equals(GatewayServiceException.class.getName()) ||
                exceptionClassName.equals(application.exception.ServiceCommunicationException.class.getName())) {
            resolvedCode = statusDescriptionResolver.getCode("503-URL");

        } else if (exception instanceof NotFoundException) {
            resolvedCode = statusDescriptionResolver.getCode("ERR-404");

        } else if (exception instanceof NotAllowedException) {
            resolvedCode = statusDescriptionResolver.getCode("405");

        } else if (isClientError(exception)) {
            resolvedCode = statusDescriptionResolver.getCode("ERR-400");

        } else {
            // Default para cualquier otra excepción no controlada
            log.error("[ERROR: {}] Error de backend no manejado que llego al GlobalExceptionHandler", requestId, exception);
            resolvedCode = statusDescriptionResolver.getCode("500");
        }

        var statusResponse = domain.dto.response.StatusResponse.builder()
                .status("error")
                .statusCode(resolvedCode.statusCode())
                .message(resolvedCode.description())
                .traceId(requestId)
                .build();

        var response = new CustomerResponse(statusResponse);

        // Es importante devolver el código de estado HTTP correcto.
        int httpStatus = Integer.parseInt(resolvedCode.statusCode().split("-")[0]);

        return Response.status(httpStatus)
                .entity(response)
                .build();
    }

    private boolean isClientError(Throwable throwable) {
        return throwable instanceof BadRequestException ||
                throwable instanceof com.fasterxml.jackson.core.JsonProcessingException ||
                throwable instanceof NullPointerException;
    }
}