package cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support;

import cokr.xit.ens.biz.traffic.cheonan.code.SndngProcessSttusCd;
import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndng;
import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.TcaElctrnNticSndngDetail;
import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldUpdate;
import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngDetailRepository;
import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.repository.TcaElctrnNticSndngRepository;
import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.accept.AcptDocKkoMd;
import cokr.xit.ens.biz.traffic.cheonan.signtalk.service.support.accept.AcptDocKtGbs;
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.Checks;
import cokr.xit.ens.core.utils.CmmnUtil;
import cokr.xit.ens.core.utils.MapDeserailizer;
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.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 TrafficCaSigntalkAcceptor implements EnsPhaseProcSupport<EnsResponseVO, String> {

    private final TcaElctrnNticSndngRepository tcaElctrnNticSndngRepository;
    private final TcaElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository;

    private final IntgrnNotiService intgrnNotiService;

    private Gson gson = new GsonBuilder().registerTypeAdapter(Map.class, new MapDeserailizer()).serializeNulls().create();


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

    /**
     * Accept 준비
     *
     * @param elctrnNticSndngIds
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public EnsResponseVO statReady(List<String> elctrnNticSndngIds) {
        try {
            AtomicInteger index = new AtomicInteger();
            String prefixExternalDocumentUuid = String.format("B-%s%s", LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmssSSS")), RandomString.make(5));
            elctrnNticSndngIds.stream()
                    .map(elctrnNticSndngId -> tcaElctrnNticSndngRepository.findById(elctrnNticSndngId).get())
                    .map(elctrnNticSndng -> elctrnNticSndngDetailRepository.findAllDecByElctrnNticSndng(elctrnNticSndng))
                    .forEach(list -> {
                                list.stream()
                                        .forEach(row -> {
                                            row.setExternalDocumentUuid(String.format("%s%09d", prefixExternalDocumentUuid, index.getAndIncrement() + 1));
                                        });
                                elctrnNticSndngDetailRepository.saveAll(list);

                            }

                    );
            return EnsResponseVO.okBuilder().build();
        } catch (Exception e) {
            return EnsResponseVO.errBuilder()
                    .errCode(EnsErrCd.ACPT500)
                    .errMsg(String.format("문서식별번호(외부) 생성에 실패 했습니다. %s", e.getMessage()))
                    .build();
        }

    }


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


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

        EnsResponseVO responseVO = null;
        TcaElctrnNticSndng elctrnNticSndng = null;
        try {
            elctrnNticSndng = tcaElctrnNticSndngRepository.findById(elctrnNticSndngId)
                    .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, String.format("일치하는 TB_ELCTRN_NTIC_SNDNG 데이터가 없습니다. [ elctrnNticSndngId %s ]", elctrnNticSndngId)));

            IntgrnNotiAcceptReqDTO reqDTO = this.convertTbInputDataToAcceptReqDTO(elctrnNticSndngDetailRepository.findAllFetchByElctrnNticSndngId(elctrnNticSndng.getElctrnNticSndngId()));

            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())) {
                elctrnNticSndng.setUpdate(FieldUpdate.builder()
                        .updusr("ENS_SYS")
                        .updtDt(LocalDateTime.now())
                        .build());
                elctrnNticSndng.setSndngProcessSttus(SndngProcessSttusCd.acptok);
                elctrnNticSndng.setErrorCn(null);
            } else {
                elctrnNticSndng.setUpdate(FieldUpdate.builder()
                        .updusr("ENS_SYS")
                        .updtDt(LocalDateTime.now())
                        .build());
                elctrnNticSndng.setSndngProcessSttus(SndngProcessSttusCd.acptfail);
                elctrnNticSndng.setErrorCn(responseVO.getErrMsg());
                if (responseVO.getResultInfo() != null && (responseVO.getResultInfo() instanceof List || responseVO.getResultInfo() instanceof Map))
                    elctrnNticSndng.setErrorDtls(gson.toJson(responseVO.getResultInfo()));
            }
        }

        return responseVO;
    }


    private IntgrnNotiAcceptReqDTO convertTbInputDataToAcceptReqDTO(List<TcaElctrnNticSndngDetail> list) {

        return IntgrnNotiAcceptReqDTO.builder()
                .vender(VenderCd.none.getCode())
                .org_cd(list.get(0).getElctrnNticSndng().getSignguCode())
                .tmplt_cd(list.get(0).getElctrnNticSndng().getTcaNhtTmplatManage().getNhtTmplatId())
                .post_bundle_title(
                        String.format("%s(%s건)-%s"
                                , list.get(0).getElctrnNticSndng().getTcaNhtTmplatManage().getNhtNm()
                                , list.get(0).getElctrnNticSndng().getSndngCo()
                                , LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMddHHmmss"))
                        )
                )
                .send_dt(list.get(0).getElctrnNticSndng().getSndngDt())
                .close_dt(list.get(0).getElctrnNticSndng().getClosDt())
                .documents(
                        list.stream()
                                .map(row -> this.createDocument(row))
                                .collect(Collectors.toList())
                )
                .build();
    }

    private Document createDocument(TcaElctrnNticSndngDetail data) throws EnsException {

        String jid = elctrnNticSndngDetailRepository.findIhidnumDecByElctrnNticSndngDetailId(data.getElctrnNticSndngDetailId());
        jid = Checks.isCheckJid(jid) ? jid : "1111111111111";

        Map<String, String> tmpltMsgData = null;
        if (!CmmnUtil.isEmpty(data.getTmpltMsgData()))
            try {
                tmpltMsgData = gson.fromJson(data.getTmpltMsgData(), Map.class);
            } catch (Exception e) {
                throw new EnsException(EnsErrCd.ACPT411, "템플릿메시지데이터의 값은 JSON 포맷만 가능 합니다.");
            }

        return Document.builder()
                .linked_uuid(data.getExternalDocumentUuid())
                .receiver(Receiver.builder()
                        .ci(null)
//                        .jid(data.getIhidnum())
                        .jid(jid)
                        .mblphon_no(null)
                        .build())
                .acpt_data(AcptData.builder()
                        .kko_md(new AcptDocKkoMd(data, MBLPAGE_URL + MBLPAGE_PATH).createDocument())
                        .kko_at(null)
                        .nv_st(null)
                        .kt_gbs(new AcptDocKtGbs(data, MBLPAGE_URL + MBLPAGE_PATH).createDocument())
                        .build())
                .xit_property(XitProperty.builder()
                        .bill_acpt_data(this.createBillAcptData(data))
                        .tmplt_msg_data(tmpltMsgData)
                        .mbl_page_data(this.createDetails(data))
                        .build())
                .build();
    }

    private EnsBillAcptReqDTO createBillAcptData(TcaElctrnNticSndngDetail data) {
        return null;
    }

    private Map<String, List<Map<String, Object>>> createDetails(TcaElctrnNticSndngDetail data) {
        try {
            Map<String, List<Map<String, Object>>> m = gson.fromJson(data.getMobilePageCn(), Map.class);
            return m;
        } catch (Exception e) {
            log.error("\"mobilePageCn\" Json Parse 실패. {}", data.getMobilePageCn());
            return null;
        }
    }


}
