package cokr.xit.ens.biz.iup.billpay.service.process;

import cokr.xit.ens.biz.iup.domain.*;
import cokr.xit.ens.biz.iup.domain.repository.TbIupBillPayHistRepository;
import cokr.xit.ens.core.exception.EnsException;
import cokr.xit.ens.core.exception.code.EnsErrCd;
import cokr.xit.ens.core.utils.CmmnUtil;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.CustomUrl;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.kko.service.process.model.KkoPayUrlRespData;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PaidTypeCd;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysHisSeCd;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.PayUseSysResCd;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.model.PayApiRespDTO;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.service.process.kit.PayUrlService;
import cokr.xit.ens.modules.common.domain.support.FieldError;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.querydsl.jpa.impl.JPAQueryFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;

@Slf4j
@RequiredArgsConstructor
@Service
public class IupKkoPayUrlService implements PayUrlService<Map<String, Object>, Map<String, Object>, PayApiRespDTO<KkoPayUrlRespData>> {

    private final JPAQueryFactory query;
    private final TbIupBillPayHistRepository tbIupBillPayHistRepository;

    private Gson gson = new GsonBuilder().disableHtmlEscaping().create();
    @Value("${contract.kakao.pay.bill.dozn.api.validate.host}")
    private String BILL_HOST;
    @Value("${contract.kakao.pay.bill.dozn.api.validate.notice}")
    private String BILL_NOTICE_URL;
    @Value("${contract.kakao.pay.bill.dozn.api.validate.prepay}")
    private String BILL_PREPAY_URL;
    @Value("${contract.kakao.pay.bill.dozn.api.validate.payresult}")
    private String BILL_PAYREUSLT_URL;


    private enum DataKeys {
        tbInputDataXit,
        responseJsonStr,
    }

    @Override
    public Map<String, Object> getData(Map<String, Object> reqParam) {
        Map<String, Object> reqData = (Map<String, Object>) reqParam.getOrDefault("data", new HashMap<>());
        final String billerUserKey = (String) reqData.getOrDefault("billerUserKey", "");

        TbInputDataXit tbInputDataXit = query.selectFrom(QTbInputDataXit.tbInputDataXit)
                .innerJoin(QTbInputDataXit.tbInputDataXit.tbInputXit, QTbInputXit.tbInputXit).fetchJoin()
                .innerJoin(QTbInputXit.tbInputXit.fsJob, QFsJob.fsJob).fetchJoin()
                .where(QTbInputDataXit.tbInputDataXit.linkedUuid.eq(billerUserKey))
                .fetchOne();

        Map<String, Object> data = new HashMap<>();
        data.put(DataKeys.tbInputDataXit.name(), tbInputDataXit);
        return data;
    }

    @Override
    public void validate(Map<String, Object> reqParam, Map<String, Object> data) {
       
        if (CmmnUtil.isEmpty(data.get(DataKeys.tbInputDataXit.name())))
            throw new EnsException(EnsErrCd.NO_DATA_FOUND, EnsErrCd.NO_DATA_FOUND.getCodeNm());
    }

    @Override
    public void callApi(Map<String, Object> reqParam, Map<String, Object> data) {
        Optional.ofNullable(createRespData(data))
                .map(kkoPayUrlRespData -> loadRespData(data, kkoPayUrlRespData));
    }


    private KkoPayUrlRespData createRespData(Map<String, Object> data) {
        TbInputDataXit tbInputDataXit = (TbInputDataXit) data.get(DataKeys.tbInputDataXit.name());
        return KkoPayUrlRespData.builder()
                .billedYearMonth(null)
                .ordinal(null)
                .expireAt(tbInputDataXit.getTbInputXit().getPayExpiresDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))
                .parameters(null)
                .customUrl(CustomUrl.builder()
                        .noticeUrl(this.BILL_HOST + this.BILL_NOTICE_URL)
                        .prepayUrl(this.BILL_HOST + this.BILL_PREPAY_URL)
                        .payResultUrl(this.BILL_HOST + this.BILL_PAYREUSLT_URL)
                        .build())
                .build();

    }

    private Map<String, Object> loadRespData(Map<String, Object> data, KkoPayUrlRespData kkoPayUrlRespData) {

        data.put(DataKeys.responseJsonStr.name(), gson.toJson(kkoPayUrlRespData));
        return data;
    }


    @Override
    public PayApiRespDTO<KkoPayUrlRespData> generateResult(Map<String, Object> reqParam, Map<String, Object> data, EnsException e) {
        if (e == null) {
            KkoPayUrlRespData kkoPayUrlRespData = gson.fromJson((String) data.get(DataKeys.responseJsonStr.name()), KkoPayUrlRespData.class);
            return PayApiRespDTO.<KkoPayUrlRespData>okBuilder()
                    .data(kkoPayUrlRespData)
                    .build();

        } else {
            return PayApiRespDTO.<KkoPayUrlRespData>errBuilder()
                    .resCode(PayUseSysResCd.GRNURL_FIND_FAILED.getCode())
                    .message(PayUseSysResCd.GRNURL_FIND_FAILED.getCodeNm())
                    .build();
        }
    }

    @Override
    public void saveHist(Map<String, Object> reqParam, Map<String, Object> data, EnsException e) {
        Map<String, Object> reqData = (Map<String, Object>) reqParam.getOrDefault("data", new HashMap<>());
        final String billerUserKey = (String) reqData.getOrDefault("billerUserKey", "");

        String errorCode = null;
        String errorMessage = null;
        if (e != null) {
            errorCode = e.getErrCd().getCode();
            errorMessage = String.format("%s %s", e.getMessage(), CmmnUtil.printStackTraceToString(e));
        }

        TbIupBillPayHist tbIupBillPayHist = TbIupBillPayHist.builder()
                .dataId(billerUserKey)
                .paidType(PaidTypeCd.kakaoPay)   
                .hisSeCd(PayUseSysHisSeCd.gnrUrl)   
                .requestData(gson.toJson(reqParam))
                .responseData((String) data.get(DataKeys.responseJsonStr.name()))
                .error(FieldError.initBuilder()
                        .errorCode(errorCode)
                        .errorMessage(errorMessage)
                        .build())
                .build();
        tbIupBillPayHistRepository.save(tbIupBillPayHist);
    }
}
