package com.banesco.infrastructure.soap;

import com.banesco.application.UpdateCardStatusRequest;
import com.banesco.commons.config.AppConf;
import com.banesco.commons.config.StatusCodes;
import com.banesco.commons.helper.JsonHelper;
import com.banesco.commons.helper.XMLHelper;
import com.banesco.commons.model.SoapEndpoint;
import com.banesco.commons.soap.client.apidebitcardoutappsvc.*;
import com.banesco.domain.ports.outbound.CardPort;
import com.banesco.infrastructure.mapper.DebitCardMapper;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.xml.bind.JAXBElement;
import jakarta.xml.ws.WebServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.cxf.frontend.ClientProxy;
import org.apache.cxf.jaxws.JaxWsProxyFactoryBean;
import org.apache.cxf.transport.http.HTTPConduit;
import org.apache.cxf.transports.http.configuration.HTTPClientPolicy;
import org.eclipse.microprofile.config.inject.ConfigProperty;

import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;


@ApplicationScoped
@Slf4j
public class CardAdapter implements CardPort {

    private Map<String, APIDebitCardOutAppSvc> SOAP_CLIENTS = new HashMap<>();
    private final AppConf appConf;
    private final DebitCardMapper debitCardMapper;
    private final SoapEndpoint paymentGenerateSOAP;

    @ConfigProperty(name = "soap.print-xml", defaultValue = "false")
    boolean mustPrintXML;

    public CardAdapter(AppConf appConf, DebitCardMapper debitCardMapper) {
        this.appConf = appConf;
        this.debitCardMapper = debitCardMapper;
        paymentGenerateSOAP = appConf.loadSoapClientConfig("soap.service.block-unblock-debit-card");
    }


    public APIDebitCardOutAppSvc getSoapClient(String domainKey) throws SocketTimeoutException {
        if (domainKey == null) {
            domainKey = appConf.SOAP_CURRENT_DOMAIN;
        }
        APIDebitCardOutAppSvc client = SOAP_CLIENTS.get(domainKey);
        if (client == null) {
            log.info("loading domainKey: {}", domainKey);
            JaxWsProxyFactoryBean factory = new JaxWsProxyFactoryBean();
            factory.setServiceClass(APIDebitCardOutAppSvc.class);
            factory.setAddress(paymentGenerateSOAP.getUrl(appConf.getDomainConfig(domainKey)));

            client = (APIDebitCardOutAppSvc) factory.create();

            HTTPConduit conduit = (HTTPConduit) ClientProxy.getClient(client).getConduit();
            HTTPClientPolicy httpClientPolicy = new HTTPClientPolicy();
            httpClientPolicy.setConnectionTimeout(paymentGenerateSOAP.getTimeout().getConnect()); // Connection timeout in milliseconds
            httpClientPolicy.setReceiveTimeout(paymentGenerateSOAP.getTimeout().getResponse()); // Receive timeout in milliseconds
            conduit.setClient(httpClientPolicy);
            SOAP_CLIENTS.put(domainKey, client);
        }

        return client;
    }

    public BlockUnblockDebitCardRs updateCardStatus(UpdateCardStatusRequest requestData) {

        BlockUnblockDebitCardRq request = debitCardMapper.toBlockUnblockDebitCardRequest(requestData);

        if (mustPrintXML) {
            JAXBElement<BlockUnblockDebitCardRq> blockUnblockDebitCardRq = debitCardMapper.objectFactory.createBlockUnblockDebitCardRq(request);
            log.info("[SOAP blockUnblockDebitCardRq]: [{}]", XMLHelper.buildXml(blockUnblockDebitCardRq));
        } else {
            log.info("[blockUnblockDebitCardRq]: [{}]", appConf.getJsonHelper().getJsonFromObject(request));
        }

        try {
            return getSoapClient(requestData.getDomain()).blockUnblockDebitCard(request);

        }catch (SocketTimeoutException e){
            log.error("SocketTimeoutException logging domain: {}, error: {}",requestData.getDomain(), e.getMessage());
            return buildErrorStatusResponse(StatusCodes.TIMEOUT_DEPENDENCY, e.getMessage());
        } catch (WebServiceException e) {
            log.error("WebServiceException logging domain: {}, error: {}",requestData.getDomain(), e.getMessage());
            return buildErrorStatusResponse(StatusCodes.FAILED_DEPENDENCY, e.getMessage());
        }



    }

    private BlockUnblockDebitCardRs buildErrorStatusResponse(StatusCodes statusCode, String message) {
        BlockUnblockDebitCardRs response = new BlockUnblockDebitCardRs();
        Status status = debitCardMapper.objectFactory.createStatus();
        status.setStatusCode(statusCode.getStatusCode());

        AdditionalStatus additionalStatus = debitCardMapper.objectFactory.createAdditionalStatus();
        additionalStatus.setStatusCode(statusCode.getStatusDesc());
        additionalStatus.setStatusCode(message);
        status.getAdditionalStatus().add(additionalStatus);

        response.getStatus().add(
                status
        );
        return response;

    }


}

