package cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support;

import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndngDetail;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldUpdate;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngDetailRepository;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngRepository;
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.DateUtil;
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.modules.kkomydoc.model.KkoMydocAcceptReqDTO;
import cokr.xit.ens.modules.kkomydoc.model.config.Document;
import cokr.xit.ens.modules.kkomydoc.model.config.Property;
import cokr.xit.ens.modules.kkomydoc.model.config.Receiver;
import cokr.xit.ens.modules.kkomydoc.model.config.XitProperty;
import cokr.xit.ens.modules.kkomydoc.service.KkoMydocService;
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.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.Arrays;
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 TrafficCcMydocAcceptor implements EnsPhaseProcSupport<EnsResponseVO, String> {

    private final ElctrnNticSndngRepository elctrnNticSndngRepository;
    private final ElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository;

    private final KkoMydocService kkoMydocService;

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

    /**
     * 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 -> elctrnNticSndngRepository.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;
        ElctrnNticSndng elctrnNticSndng = null;
        try {
            elctrnNticSndng = elctrnNticSndngRepository.findById(elctrnNticSndngId)
                    .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, String.format("일치하는 TB_ELCTRN_NTIC_SNDNG 데이터가 없습니다. [ elctrnNticSndngId %s ]", elctrnNticSndngId)));

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

            EnsResponseVO reqResp = kkoMydocService.accept(reqDTO);


            if (EnsErrCd.OK.equals(reqResp.getErrCode())) {
                resultInfo.put("sendMastId", (Long) ((Map<String, Object>) reqResp.getResultInfo()).get("sendMastId"));
                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("02"); 
                elctrnNticSndng.setErrorCn(null);
            } else {
                elctrnNticSndng.setUpdate(FieldUpdate.builder()
                        .updusr("ENS_SYS")
                        .updtDt(LocalDateTime.now())
                        .build());
                elctrnNticSndng.setSndngProcessSttus("99"); 
                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 KkoMydocAcceptReqDTO convertTbInputDataToAcceptReqDTO(List<ElctrnNticSndngDetail> list) {

        return KkoMydocAcceptReqDTO.builder()
                .vender(VenderCd.intech.getCode())
                .org_cd(list.get(0).getElctrnNticSndng().getSignguCode())
                .tmplt_cd(list.get(0).getElctrnNticSndng().getNhtTmplatManage().getNhtTmplatId())
                .post_bundle_title(
                        String.format("%s(%s건)-%s"
                                , list.get(0).getElctrnNticSndng().getNhtTmplatManage().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 -> createDocument(row))
                                .collect(Collectors.toList())
                )
                .build();
    }

    private Document createDocument(ElctrnNticSndngDetail data) throws EnsException {

        return Document.builder()
                .external_document_uuid(data.getExternalDocumentUuid())
                .hash(null)
                .common_categories(Arrays.asList("NOTICE"))
                .read_expired_at(DateUtil.dateToAbsTimeSec(data.getElctrnNticSndng().getClosDt()))
//                .read_expired_sec()
                .receiver(this.createReceiver(data))
                .property(this.createProperty(data))
                .bridge(null)
                .xit_property(this.createXitProperty(data))
                .build();
    }

    private Receiver createReceiver(ElctrnNticSndngDetail data) {
        return Receiver.builder()
                .ci(null)
                .phone_number(null)
                .name(null)
                .birthday(null)
                .is_required_verify_name(null)
                .build();
    }

    private Property createProperty(ElctrnNticSndngDetail data) {
        return Property.builder()
                .link(data.getElctrnNticSndng().getNhtTmplatManage().getRedirectUrl())
                .payload(null)
//                .external_document_uuid(data.getExternalDocumentUuid())
                .build();
    }

    private XitProperty createXitProperty(ElctrnNticSndngDetail data) {
        Map<String, List<Map<String, Object>>> mobilePage = new HashMap<>();
        mobilePage.put("details", this.createDetails(data));

        String jid = elctrnNticSndngDetailRepository.findIhidnumDecByElctrnNticSndngDetailId(data.getElctrnNticSndngDetailId());
        return XitProperty.builder()
                .mbl_page_data(mobilePage)
//                .ci_trans_use_yn("Y")
//                .jid(data.getIhidnum())
                .jid(Checks.isCheckJid(jid) ? jid : "1111111111111")
                .tmplt_msg_data(null)
                .build();
    }

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


}
