package com.banesco.infrastructure.rest.repositories;

import com.banesco.common.application.exception.BanBackendException;
import com.banesco.common.application.exception.BanRuntimeException;
import com.banesco.common.domain.dto.bian.response.BianStatusResponse;
import com.banesco.common.domain.model.ApiConfig;
import com.banesco.common.infraestructure.helpers.JsonHelper;
import com.banesco.common.infraestructure.helpers.LoggerHelper;
import com.banesco.commons.config.StatusCodes;
import com.banesco.infrastructure.dtos.card.UpdateCardStatusRequest;
import com.banesco.infrastructure.dtos.card.soap.BlockUnblockDebitCardRs;
import com.banesco.infrastructure.dtos.osb.AdditionalStatus;
import com.banesco.infrastructure.dtos.osb.Status;
import com.banesco.infrastructure.rest.clients.BusUpdateCardStatusRestClient;
import io.quarkus.runtime.annotations.RegisterForReflection;
import jakarta.ws.rs.ClientErrorException;
import jakarta.ws.rs.core.Response;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.microprofile.rest.client.RestClientBuilder;

import java.net.URI;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@RegisterForReflection
@Slf4j
public class PaymentCardRepository {


    private final BusUpdateCardStatusRestClient restClient;

    private final String OPERATION_NAME = "PRV_UPDATE_CARD_STATUS";


    public PaymentCardRepository(ApiConfig apiConfig) {

        restClient = RestClientBuilder.newBuilder().baseUri(
                        URI.create(apiConfig.getUrl())
                ).
                connectTimeout(apiConfig.getTimeout().getConnect(), TimeUnit.MILLISECONDS)
                .readTimeout(apiConfig.getTimeout().getResponse(), TimeUnit.MILLISECONDS)
                .build(BusUpdateCardStatusRestClient.class);

    }


    public void updateCardStatus(String requestId, UpdateCardStatusRequest request) {

        BlockUnblockDebitCardRs response = null;
        try {


            log.info(LoggerHelper.buildInfoPrivateRequest(requestId, OPERATION_NAME, JsonHelper.getJsonFromObject(request)));

            Response responseHttp = restClient.invoke(request);

            response = responseHttp.readEntity(BlockUnblockDebitCardRs.class);
            log.info(LoggerHelper.buildInfoPrivateResponse(requestId, OPERATION_NAME, JsonHelper.getJsonFromObject(response)));


            if (response.getMsgRsHdr() != null &&
                    response.getMsgRsHdr().getFinalStatusRequest() != null &&
                    response.getMsgRsHdr().getFinalStatusRequest().equals("0001")
                    && response.getMsgRsHdr().getDetailReg() != null
                    && response.getMsgRsHdr().getDetailReg().contains("con exito")
            ) {
                return;
            }

        } catch (ClientErrorException e) {
            log.error(LoggerHelper.buildError(OPERATION_NAME + " - " + requestId, "Error calling API: " + e.getMessage()));
            throw new BanRuntimeException(StatusCodes.FAILED_DEPENDENCY);
        } catch (Exception e) {
            log.error(LoggerHelper.buildError(OPERATION_NAME + " - " + requestId, "Error interno calling API: " + e.getMessage()));
            throw new BanRuntimeException(StatusCodes.INTERNAL_ERROR);
        }


        if (response.getStatus() != null &&
                response.getStatus().get(0) != null &&
                !response.getStatus().get(0).getStatusCode().equals("000")) {
            throw new BanBackendException(response.getStatus().get(0).getStatusCode(), response.getStatus().get(0).getStatusDesc());
        }

        validateSoapResponseStatus(response.getStatus().get(0));

    }


    /**
     * Validate Property Status If has some error and throw Exception with Code  or join(-) codes is no equals to 000
     *
     * @param status
     */
    private BianStatusResponse validateSoapResponseStatus(Status status) {

        // Get Back Error
        Map<String, String> errors = new HashMap<>();
        AdditionalStatus additionalStatus = null;
        if (status.getAdditionalStatus() != null) {
            for (AdditionalStatus additionalStatusCurrent : status.getAdditionalStatus()) {
                if (additionalStatusCurrent.getStatusCode().equals("000")) {
                    break;
                } else {
                    errors.put(additionalStatusCurrent.getStatusCode(), additionalStatusCurrent.getStatusCode());
                    if (additionalStatus == null) {
                        additionalStatus = additionalStatusCurrent;
                    }
                }
            }

        }
        if (!errors.values().isEmpty()) {
            /**
             * Concat errors
             */

            throw new BanBackendException(errors.values().stream().collect(Collectors.joining("-")).toString(),
                    additionalStatus.getStatusDesc());
        }

        throw new BanRuntimeException(StatusCodes.INTERNAL_ERROR);


    }
}
