package com.banesco.module.legal_customer_product_directory.application.service;

import com.banesco.common.application.helper.MessageHelper;
import com.banesco.common.domain.exception.HttpStatusCodeException;
import com.banesco.common.domain.model.ApiResponse;
import com.banesco.common.domain.model.AppIdConfig;
import com.banesco.common.infrastructure.config.ApiAllowedConfig;
import com.banesco.common.infrastructure.context.RequestContext;
import com.banesco.module.legal_customer_product_directory.application.usecase.DomainUseCase;
import com.banesco.module.legal_customer_product_directory.application.usecase.LegalCustomerProductDirectoryUseCase;
import com.banesco.module.legal_customer_product_directory.domain.dto.request.LegalCustomerProductDirectoryRequest;
import com.banesco.module.legal_customer_product_directory.domain.dto.response.LegalCustomerProductDirectoryResponse;
import com.banesco.module.security_trace.application.usecase.SecurityTraceUseCase;
import com.banesco.module.security_trace.domain.dto.response.SecurityTraceResponse;
import com.banesco.module.service_status.application.usecase.ServiceStatusUseCase;
import com.banesco.module.service_status.domain.dto.request.ServiceStatusRequest;
import com.banesco.module.service_status.domain.dto.response.ServiceStatusResponse;
import io.netty.util.internal.StringUtil;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.core.Response;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Objects;
import java.util.Optional;

@Slf4j
@ApplicationScoped
public class LegalCustomerProductDirectoryService implements LegalCustomerProductDirectoryUseCase {

    private final MessageHelper messageHelper;
    private final ServiceStatusUseCase serviceStatusUseCase;
    private final SecurityTraceUseCase securityTraceUseCase;
    private final DomainUseCase domainUseCase;

    private final List<AppIdConfig> appIdsAllowed;

    @Inject
    public LegalCustomerProductDirectoryService(
        ApiAllowedConfig apiAllowedConfig,
        MessageHelper messageHelper,
        ServiceStatusUseCase serviceStatusUseCase,
        SecurityTraceUseCase securityTraceUseCase,
        DomainUseCase domainUseCase
    ) {
        this.messageHelper = messageHelper;
        this.serviceStatusUseCase = serviceStatusUseCase;
        this.securityTraceUseCase = securityTraceUseCase;
        this.domainUseCase = domainUseCase;
        this.appIdsAllowed = apiAllowedConfig.getAppIdAllowed();
    }

    @Override
    public Response execute(
        LegalCustomerProductDirectoryRequest request
    ) {
        log.info("Iniciando ejecucion para el cliente: {}", request.getCustomerId());

        Response response = null;
        LegalCustomerProductDirectoryRequest requestFromAppId = request;
        long startTime = System.currentTimeMillis();

        try {
            requestFromAppId = getRequestFromAppId(request);

            if(StringUtil.isNullOrEmpty(requestFromAppId.getCustomerId())) {
                log.error("Error en el codigo del cliente vacio");
                throw HttpStatusCodeException.badRequest("VRN01");
            }

            if(!isServiceStatusActive(requestFromAppId)) {
                log.info("Estatus del servicio no disponible: {}", requestFromAppId.getCustomerId());
                throw HttpStatusCodeException.serviceUnavailable("VRN04");
            }

            ApiResponse<LegalCustomerProductDirectoryResponse> apiResponse = domain(requestFromAppId);

            response = messageHelper.handleSuccess(
                apiResponse.getData(),
                apiResponse.getStatusResponse().getStatusCode()
            );
        } catch (HttpStatusCodeException e) {
            log.error("Excepcion HTTP del api de dominio: {} - {}", e.getStatusCode(), e.getErrorCode());
            response = messageHelper.handleException(e);
        } catch (Exception e) {
            log.error("Excepcion generica del api de dominio: {}", e.getMessage());
            response = messageHelper.handleGenericException(e);
        } finally {
            long endTime = System.currentTimeMillis();
            securityTrace(requestFromAppId, response, startTime, endTime);
        }

        return response;
    }

    private LegalCustomerProductDirectoryRequest getRequestFromAppId(
        LegalCustomerProductDirectoryRequest request
    ) {
        if(appIdsAllowed.isEmpty()) {
            log.info(
                "Configuracion de la Lista App ID no disponible: {} -> {}",
                request.getCustomerId(),
                request.getAppId()
            );
            throw HttpStatusCodeException.unauthorized("401");
        }

        Optional<AppIdConfig> appIdAllowed = appIdsAllowed.stream()
            .filter(config -> config.getAppId().equals(request.getAppId()))
            .findFirst();

        if(appIdAllowed.isEmpty()) {
            log.info("App ID no habilitado: {} -> {}", request.getCustomerId(), request.getAppId());
            throw HttpStatusCodeException.unauthorized("401");
        }

        AppIdConfig appIdConfig = appIdAllowed.get();

        if(!request.hasValidRequestParameters(appIdConfig)) {
            log.info("App ID sin configuracion: {} -> {}", request.getCustomerId(), request.getAppId());
            throw HttpStatusCodeException.unauthorized("401");
        }

        return request.fromAppIdConfig(request, appIdConfig);
    }

    private ApiResponse<LegalCustomerProductDirectoryResponse> domain(
        LegalCustomerProductDirectoryRequest request
    ) {
        log.info("Ejecutando llamada al api de dominio: {}", request.getCustomerId());
        return domainUseCase.execute(request, LegalCustomerProductDirectoryResponse.class);
    }

    private boolean isServiceStatusActive(
        LegalCustomerProductDirectoryRequest request
    ) {
        log.info("Ejecutando llamada al api de la consulta del estatus del servicio");

        boolean isServiceActive = false;

        try {
            ServiceStatusResponse response = serviceStatusUseCase.execute(
                ServiceStatusRequest.builder()
                    .applicationId(request.getAppId())
                    .transactionId(RequestContext.getRequestId())
                    .build(),
                ServiceStatusResponse.class
            );

            isServiceActive = Objects.equals(response.getStatus(), "A");
        } catch (HttpStatusCodeException e) {
            log.info(
                "Error HTTP al ejecutar la consulta del estatus del servicio: {} -> {}",
                e.getStatusCode(),
                e.getMessage()
            );
        } catch (Exception e) {
            log.info(
                "Error al ejecutar la consulta del estatus del servicio: {}",
                e.getMessage()
            );
        }

        return isServiceActive;
    }

    private void securityTrace(
        LegalCustomerProductDirectoryRequest request,
        Response response,
        long startTime,
        long endTime
    ) {
        log.info("Ejecutando llamada al api de la traza de seguridad");

        try {
            securityTraceUseCase.execute(
                request, response,
                startTime, endTime,
                SecurityTraceResponse.class
            );
        } catch (HttpStatusCodeException e) {
            log.info(
                "Error HTTP al ejecutar la traza de seguridad: {} -> {}",
                e.getStatusCode(),
                e.getMessage()
            );
        } catch (Exception e) {
            log.info("Error al ejecutar la traza de seguridad: {}", e.getMessage());
        }
    }
}