package cokr.xit.ens.modules.common.ctgy.nicedici.support.rest;

import cokr.xit.ens.core.aop.EnsResponseVO;
import cokr.xit.ens.core.exception.code.EnsErrCd;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.code.NiceCiApiCd;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.domain.NiceCiSymkeyMng;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.domain.repository.NiceCiSymkeyMngRepository;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.NiceCiRespVO;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyCiResp;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyGenerateTokenResp;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodyPubkeyResp;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.model.conf.DataBodySymkeyResp;
import cokr.xit.ens.modules.common.ctgy.nicedici.support.rest.utils.SymmetricKey;
import com.fasterxml.jackson.databind.ObjectMapper;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Optional;

@Log4j2
@Component
@RequiredArgsConstructor
public class NiceCiGenerator {

    private final NiceCiSymkeyMngRepository niceCiSymkeyMngRepository;

    @Value("${contract.nice.dici.rest.host}")
    private String HOST;
    @Value("${contract.nice.dici.rest.api.generate-token}")
    private String API_GENERATE_TOKEN;
    @Value("${contract.nice.dici.rest.api.revoke-token}")
    private String API_REVOKE_TOKEN;
    @Value("${contract.nice.dici.rest.api.publickey}")
    private String API_PUBLICKEY;
    @Value("${contract.nice.dici.rest.api.symmetrickey}")
    private String API_SYMMETRICKEY;
    @Value("${contract.nice.dici.rest.api.ci}")
    private String API_CI;

    public EnsResponseVO initialKey(String clientId, String clientSecret) {

        NiceCiApiExecutor executor = buildExecutor(clientId, clientSecret);
        try {

            NiceCiRespVO<DataBodyGenerateTokenResp> tokenResponseVO = executor.token();
            if (!NiceCiApiCd.OK.equals(tokenResponseVO.getErrCode()))
                return EnsResponseVO.<String>errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(tokenResponseVO.getErrCode().getCode() + " " + tokenResponseVO.getErrMsg()).build();

            NiceCiRespVO<DataBodyPubkeyResp> pubkeyResponseVO = executor.pubkey();
            if (!NiceCiApiCd.OK.equals(pubkeyResponseVO.getErrCode()))
                return EnsResponseVO.<String>errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(pubkeyResponseVO.getErrCode().getCode() + " " + pubkeyResponseVO.getErrMsg()).build();

//            NiceCiRespVO<DataBodySymkeyResp> symkeyResponseVO = executor.symkey();
//            if (!NiceCiApiCd.OK.equals(symkeyResponseVO.getErrCode()))
//                return EnsResponseVO.<String>errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(symkeyResponseVO.getErrCode().getCode() + " " + symkeyResponseVO.getErrMsg()).build();
            ObjectMapper mapper = new ObjectMapper();
            DataBodySymkeyResp dataBodySymkeyResp = null;
            if (SymmetricKey.isValidStat(clientId)) {
                dataBodySymkeyResp = SymmetricKey.getInstance().getData(clientId);
            } else {   
               
//                Optional<NiceCiSymkeyMng> niceCiSymkeyMng = niceCiSymkeyMngRepository.findByClientIdAndPubkey(clientId, pubkeyResponseVO.getResultInfo().getPublicKey());
                List<NiceCiSymkeyMng> niceCiSymkeyMngs = niceCiSymkeyMngRepository.findAllByClientIdAndPubkeyOrderByRegistDtDesc(clientId, pubkeyResponseVO.getResultInfo().getPublicKey());
                Optional<NiceCiSymkeyMng> niceCiSymkeyMng = Optional.ofNullable(niceCiSymkeyMngs == null || niceCiSymkeyMngs.isEmpty() ? null : niceCiSymkeyMngs.get(0));

               
                if (niceCiSymkeyMng.isPresent()
                        && (Long.parseLong(niceCiSymkeyMng.get().getExpireDt()) > Long.parseLong(LocalDateTime.now().plusDays(1).format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))))) {
                    dataBodySymkeyResp = mapper.readValue(niceCiSymkeyMng.get().getRespJsonData(), DataBodySymkeyResp.class);

                   
                    SymmetricKey.getInstance(clientId, dataBodySymkeyResp);

                } else {
                   
                    NiceCiRespVO<DataBodySymkeyResp> symkeyResponseVO = executor.symkey();
                    if (!NiceCiApiCd.OK.equals(symkeyResponseVO.getErrCode()))
                        return EnsResponseVO.<String>errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(symkeyResponseVO.getErrCode().getCode() + " " + symkeyResponseVO.getErrMsg()).build();
                    dataBodySymkeyResp = symkeyResponseVO.getResultInfo();

                   
                    niceCiSymkeyMngRepository.save(NiceCiSymkeyMng.builder()
                            .clientId(clientId)
                            .pubkey(pubkeyResponseVO.getResultInfo().getPublicKey())
                            .symkey(dataBodySymkeyResp.getKey())
                            .expireDt(dataBodySymkeyResp.getSymkeyStatInfo().getCurValidDtim())
                            .version(dataBodySymkeyResp.getSymkeyStatInfo().getCurSymkeyVersion())
                            .iv(dataBodySymkeyResp.getIv())
                            .hmacKey(dataBodySymkeyResp.getHmacKey())
                            .respJsonData(mapper.writeValueAsString(dataBodySymkeyResp))
                            .build());
                }
            }


            return EnsResponseVO.<String>okBuilder().build();
        } catch (Exception e) {
            return EnsResponseVO.<String>errRsltBuilder().errCode(EnsErrCd.ERR699).errMsg(e.getMessage()).build();
        }
    }

    public EnsResponseVO<String> getCI(String jid, String clientIp, String clientId, String clientSecret) {

        NiceCiApiExecutor executor = buildExecutor(clientId, clientSecret);

        try {
            NiceCiRespVO<DataBodyCiResp> ciResponseVO = executor.ci(jid, clientIp);
            if (!NiceCiApiCd.OK.equals(ciResponseVO.getErrCode()))
                return EnsResponseVO.<String>errRsltBuilder().errCode(EnsErrCd.ERR600).errMsg(ciResponseVO.getErrCode().getCode() + " " + ciResponseVO.getErrMsg()).build();


            return EnsResponseVO.<String>okBuilder().resultInfo(ciResponseVO.getResultInfo().getDecEncData().getCi1()).build();
        } catch (Exception e) {
            return EnsResponseVO.<String>errRsltBuilder().errCode(EnsErrCd.ERR699).errMsg(e.getMessage()).build();
        }
    }

    private NiceCiApiExecutor buildExecutor(String clientId, String clientSecret) {
        return NiceCiApiExecutor.builder()
                .HOST(this.HOST)
                .CLIENT_ID(clientId)
                .CLIENT_SECRET(clientSecret)
                .API_GENERATE_TOKEN(this.API_GENERATE_TOKEN)
                .API_REVOKE_TOKEN(this.API_REVOKE_TOKEN)
                .API_PUBLICKEY(this.API_PUBLICKEY)
                .API_SYMMETRICKEY(this.API_SYMMETRICKEY)
                .API_CI(this.API_CI)
                .build();
    }
}
