package infrastructure.client.servicestatus.adapter;

import application.exception.GatewayServiceException;
import application.exception.ServiceCommunicationException;
import application.port.input.command.ServiceStatusCommand;
import com.banesco.common.infraestructure.helpers.LoggerHelper;
import domain.model.ServiceStatus;
import domain.repository.IStatusPort;
import infrastructure.client.servicestatus.api.ServiceStatusClient;
import infrastructure.mapper.ServiceStatusMapper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.WebApplicationException;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.rest.client.inject.RestClient;

@Slf4j
@ApplicationScoped
public class ServiceStatusAdapter implements IStatusPort {

    private final ServiceStatusClient client;

    @Inject
    public ServiceStatusAdapter(@RestClient ServiceStatusClient client) {
        this.client = client;
    }

    /**
     * Implementa la comunicación con la API externa para obtener el estado de un servicio.
     *
     * @param command El comando de dominio con los datos de la consulta.
     * @param requestId El ID de la solicitud para trazabilidad.
     * @return Un objeto {@link ServiceStatus} con el estado del servicio.
     * @throws GatewayServiceException si el servicio externo no es accesible, devuelve un error,
     * o la respuesta tiene un formato inesperado.
     */
    @Override
    public ServiceStatus getServiceStatus(ServiceStatusCommand command, String requestId) {
        try {
            log.debug(LoggerHelper.buildInfoPrivateRequest(requestId, "Adaptador: Mapeando Command a DTO para Service Status"));
            var requestDto = ServiceStatusMapper.toRequestDto(command);

            log.info(LoggerHelper.buildInfoPrivateRequest(requestId, "Llamando al servicio de service status", requestDto));
            var response = client.getServiceStatus(requestId, requestDto);

            log.info(LoggerHelper.buildInfoPrivateResponse(requestId, "Respuesta del servicio de service status", response));

            // Validación de contrato: asegura que la respuesta no sea nula o inválida.
            if (response == null || response.getStatus() == null) {
                log.warn(LoggerHelper.buildError(requestId, "Respuesta invalida o nula del servicio de service status."));
                throw new GatewayServiceException("Respuesta invalida del servicio externo de estado.");
            }

            return ServiceStatusMapper.toEntity(response);

        } catch (WebApplicationException ex) {
            var errorResponse = ex.getResponse();
            var status = errorResponse.getStatus();
            String errorDetails;

            // Verifica si el Content-Type es HTML
            if (errorResponse.getMediaType() != null && errorResponse.getMediaType().toString().contains("text/html")) {
                errorDetails = "Se recibio una respuesta HTML no esperada del servicio.";
                log.error(LoggerHelper.buildError(requestId,
                        String.format("Error HTTP %s del servicio de service status. %s", status, errorDetails)));
            } else {
                // Si no es HTML, probablemente es un error JSON que sí queremos ver.
                var errorBody = errorResponse.readEntity(String.class);
                // Aun así, es buena idea truncarlo por si es muy largo
                errorDetails = errorBody.substring(0, Math.min(errorBody.length(), 1000));
                log.error(LoggerHelper.buildError(requestId,
                        String.format("Error HTTP no manejado del servicio de service status. Status: %s. Body: %s", status, errorDetails)));
            }

            throw new GatewayServiceException("Error en el servicio de service status: " + errorDetails);
        } catch (RuntimeException ex) {
            // Captura errores de más bajo nivel (red, timeouts, host desconocido, etc.).
            log.error(LoggerHelper.buildError(
                    requestId,
                    String.format("Error de comunicacion con el servicio de estado: %s", ex.getMessage())
            ));

            throw new ServiceCommunicationException("No se pudo comunicar con el servicio externo de service status", ex);
        }
    }
}