package cokr.xit.ens.biz.iup.signtalk.service.support;

import cokr.xit.ens.biz.iup.code.IupPrcsCd;
import cokr.xit.ens.biz.iup.code.IupSendTypeCd;
import cokr.xit.ens.biz.iup.domain.TbInputDataXit;
import cokr.xit.ens.biz.iup.domain.TbInputXit;
import cokr.xit.ens.biz.iup.domain.repository.TbInputDataXitRepository;
import cokr.xit.ens.biz.iup.domain.repository.TbInputXitRepository;
import cokr.xit.ens.biz.iup.signtalk.service.support.accept.AcptDocKkoMd;
import cokr.xit.ens.biz.iup.signtalk.service.support.accept.AcptDocNvSt;
import cokr.xit.ens.core.aop.EnsResponseVO;
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.biztmplt.EnsPhaseProcSupport;
import cokr.xit.ens.modules.common.code.VenderCd;
import cokr.xit.ens.core.model.EnsBillAcptReqDTO;
import cokr.xit.ens.modules.common.ctgy.intgrnbill.support.code.BillSeCd;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiAcceptReqDTO;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.AcptData;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.Document;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.Receiver;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.config.XitProperty;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import net.bytebuddy.utility.RandomString;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class IupSigntalkAcceptor implements EnsPhaseProcSupport<EnsResponseVO, Long> {

    private final TbInputXitRepository tbInputXitRepository;
    private final TbInputDataXitRepository tbInputDataXitRepository;

    private final IntgrnNotiService intgrnNotiService;


    @Value("${xit.mblpage.postse.intgrn.url}")
    private String MBLPAGE_URL;
    @Value("${xit.mblpage.postse.intgrn.path}")
    private String MBLPAGE_PATH;


    /**
     * Accept 준비
     *
     * @param lnkInputIds
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public EnsResponseVO statReady(List<Long> lnkInputIds) {


        try {
            AtomicInteger index = new AtomicInteger();
            String prefixLinkedUuid = String.format("B-ST%s%s", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")), RandomString.make(5));
            lnkInputIds.stream()
                    .map(lnkInputId -> tbInputXitRepository.findById(lnkInputId).get())
                    .map(tbinput -> tbInputDataXitRepository.findAllByTbInputXit(tbinput))
                    .forEach(list -> {
                                list.stream()
                                        .forEach(row -> {
                                            log.info(row.toString());

//                                            row.setLinkedUuid(String.format("%s%05d", prefixLinkedUuid, index.getAndIncrement() + 1));
                                            row.setLinkedUuid(row.getDataId());
                                        });
                                tbInputDataXitRepository.saveAll(list);

                            }

                    );
        } catch (Exception e) {
            return EnsResponseVO.errBuilder()
                    .errCode(EnsErrCd.ACPT500)
                    .errMsg(String.format("연계식별UUID 생성에 실패 했습니다. %s", e.getMessage()))
                    .build();
        }


        EnsResponseVO respVO = null;
        try {
            /**
             * 필수값 확인
             */
            if (CmmnUtil.isEmpty(lnkInputIds))
                throw new EnsException(EnsErrCd.ACPT410, "연계입수아이디(은)는 필수조건 입니다.");

            /**
             * 저장
             *  -. 발송마스터의 상태를 "대상이관등록(TGRI)" 으로 변경 한다.
             */

            List<Long> resultInfo = tbInputXitRepository.findAllByLnkInputIdIn(lnkInputIds).stream()
                    .map(row -> {
                        row.setUpdId("ENS_SYS");
                        row.setPrcsCd(IupPrcsCd.TGRI);
                        return row.getLnkInputId();
                    })
                    .collect(Collectors.toList());


            respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build();
        } catch (EnsException e) {

            respVO = EnsResponseVO.errBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).build();
        } catch (Exception e) {

            respVO = EnsResponseVO.errBuilder().errCode(EnsErrCd.ACPT999).errMsg(e.getMessage()).build();
        }

        return respVO;
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public EnsResponseVO statBegin(Long arg) {
        log.info("no process");
        return null;
    }


    /**
     * 인증톡 전자고지 접수
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public EnsResponseVO execute(Long lnkInputId) {
        Map<String, Long> resultInfo = new HashMap<>();
        resultInfo.put("lnkInputId", lnkInputId);

        EnsResponseVO responseVO = null;
        TbInputXit tbInputXit = null;
        try {
            tbInputXit = tbInputXitRepository.findById(lnkInputId)
                    .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, String.format("일치하는 TB_INPUT_XIT 데이터가 없습니다. [ lnkInputId %s ]", lnkInputId)));

            IntgrnNotiAcceptReqDTO reqDTO = this.convertTbInputDataToAcceptReqDTO(tbInputDataXitRepository.findAllFetchByLnkInputId(tbInputXit.getLnkInputId()));

            EnsResponseVO reqResp = intgrnNotiService.accept(reqDTO);


            if (EnsErrCd.OK.equals(reqResp.getErrCode())) {
                resultInfo.put("intSendMastId", (Long) ((Map<String, Object>) reqResp.getResultInfo()).get("intSendMastId"));
                responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build();
            } else {
                responseVO = EnsResponseVO.errRsltBuilder()
                        .errCode(reqResp.getErrCode())
                        .errMsg(reqResp.getErrMsg())
                        .resultInfo(reqResp.getResultInfo())
                        .build();
            }
        } catch (EnsException e) {
            responseVO = EnsResponseVO.errRsltBuilder()
                    .errCode(e.getErrCd())
                    .errMsg(String.format("인증톡 \"접수\" 처리 실패. [%s] %s", e.getErrCd().getCode(), e.getMessage()))
                    .resultInfo(resultInfo)
                    .build();

        } catch (Exception e) {
            responseVO = EnsResponseVO.errRsltBuilder()
                    .errCode(EnsErrCd.ACPT500)
                    .errMsg(String.format("인증톡 \"접수\" 처리 실패. %s", e.getMessage()))
                    .resultInfo(resultInfo)
                    .build();

        } finally {
            if (EnsErrCd.OK.equals(responseVO.getErrCode())) {
                tbInputXit.setUpdId("ENS_SYS");
                tbInputXit.setPrcsCd(IupPrcsCd.TGRC);
                tbInputXit.setErrMsg(null);
            } else {
                tbInputXit.setUpdId("ENS_SYS");
                tbInputXit.setPrcsCd(IupPrcsCd.TGRF);
                tbInputXit.setErrMsg(responseVO.getErrMsg());
            }
        }

        return responseVO;
    }


    private IntgrnNotiAcceptReqDTO convertTbInputDataToAcceptReqDTO(List<TbInputDataXit> list) {

        return IntgrnNotiAcceptReqDTO.builder()
                .vender(VenderCd.none.getCode())
                .org_cd(list.get(0).getTbInputXit().getOrgCd())
                .tmplt_cd(list.get(0).getTbInputXit().getFsJob().getJobCd())
                .post_bundle_title(
                        String.format("%s(%s건)-%s"
                                , IupSendTypeCd.KP.getCodeNm()
                                , list.get(0).getTbInputXit().getTotCnt()
                                , LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
                        )
                )
                .send_dt(list.get(0).getTbInputXit().getRunDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))
                .close_dt(list.get(0).getTbInputXit().getExpiresDt().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss")))
                .documents(
                        list.stream()
                                .map(row -> createDocument(row))
                                .collect(Collectors.toList())
                )
                .build();
    }

    private Document createDocument(TbInputDataXit data) throws EnsException {

        Gson gson = new GsonBuilder().disableHtmlEscaping().create();

        return Document.builder()
                .linked_uuid(data.getLinkedUuid())
                .receiver(Receiver.builder()
                        .ci(null)
                        .jid(data.getSid())
                        .mblphon_no(data.getMoblphonNo())
                        .build())
                .acpt_data(AcptData.builder()
                        .kko_md(new AcptDocKkoMd(data, MBLPAGE_URL + MBLPAGE_PATH).createDocument())
                        .kko_at(null)

//                        .nv_st(new AcptDocNvSt(data, NV_ST_ORG_ID, MBLPAGE_URL + MBLPAGE_PATH).createDocument())
                        .nv_st(new AcptDocNvSt(data, null, MBLPAGE_URL + MBLPAGE_PATH).createDocument())
                        .build())
                .xit_property(XitProperty.builder()
                        .bill_acpt_data(this.createBillAcptData(data))
                        .tmplt_msg_data(CmmnUtil.isEmpty(data.getMsgData()) ? null : gson.fromJson(data.getMsgData().replace("~~@@!!", "#{").replace("!!@@~~", "}"), Map.class))
                        .mbl_page_data(CmmnUtil.isEmpty(data.getMsgDtlData()) ? null : gson.fromJson(data.getMsgDtlData(), Map.class))
                        .build())
                .build();
    }


    private EnsBillAcptReqDTO createBillAcptData(TbInputDataXit data) {
        return EnsBillAcptReqDTO.builder()
                .billUid(null)
                .billerUserKey(data.getLinkedUuid())
                .billSe(BillSeCd.privt)
                .build();
    }


}
