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.code.SndngResultSttusCd;
import cokr.xit.ens.biz.traffic.cheonan.code.SndngSeCd;
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.TcaElctrnNticSndngResult;
import cokr.xit.ens.biz.traffic.cheonan.signtalk.domain.embeded.FieldCreate;
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.domain.repository.TcaElctrnNticSndngResultRepository;
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.ctgy.intgrnnoti.model.IntgrnDetailStatVO;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnNotiRsltRespDTO;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.IntgrnNotiService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class TrafficCaSigntalkFetcher implements EnsPhaseProcSupport<EnsResponseVO, String> {

    private final TcaElctrnNticSndngRepository tcaElctrnNticSndngRepository;
    private final TcaElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository;

    private final TcaElctrnNticSndngResultRepository tcaElctrnNticSndngResultRepository;

    private final IntgrnNotiService intgrnNotiService;


    /**
     * Fetch 준비
     *
     * @param elctrnNticSndngIds
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public EnsResponseVO statReady(List<String> elctrnNticSndngIds) {
        log.info("no process");
        return null;
    }


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


    /**
     * 인증톡 발송(성공/실패) 자료에 대한 결과 가져오기
     *
     * @param elctrnNticSndngId
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public EnsResponseVO execute(String elctrnNticSndngId) {
        EnsResponseVO responseVO = null;
        Map<String, Object> resultInfo = new HashMap<>();
        resultInfo.put("elctrnNticSndngId", elctrnNticSndngId);

        IntgrnNotiRsltRespDTO respDTO = null;
        try {
            Long intSendMastId = elctrnNticSndngDetailRepository.findLastSendMastIdByElctrnNticSndngId(elctrnNticSndngId)
                    .orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 ENS 접수자료가 없습니다."));
            resultInfo.put("intSendMastId", intSendMastId);


            EnsResponseVO apiRespVO = intgrnNotiService.sendResultProvide(intSendMastId);
            respDTO = (IntgrnNotiRsltRespDTO) apiRespVO.getResultInfo();


            List<TcaElctrnNticSndngResult> tcaElctrnNticSndngResults = respDTO.getDocuments().stream()
                    .map(row -> {
                        return TcaElctrnNticSndngResult.builder()
                                .sndngSe(SndngSeCd.valueOfEnum(row.getCurPostSe().getCode()))
                                .elctrnNticSndngDetailId(elctrnNticSndngDetailRepository.findByExternalDocumentUuid(row.getLinkedUuid())
                                        .orElse(new TcaElctrnNticSndngDetail())
                                        .getElctrnNticSndngDetailId())
                                .sndngResultSttus(this.sndngResultSttus(row))
                                .requstDt(row.getDocSentDt())
                                .inqireDt(row.getDocReceivedDt())
                                .readngDt(row.getDocReadFrstDt())
                                .errorCn(CmmnUtil.isEmpty(row.getErrorMessage()) ? null : row.getErrorMessage())
                                .create(FieldCreate.builder()
                                        .register("ENS_SYS")
                                        .registDt(LocalDateTime.now())
                                        .build())
                                .build();
                    })
                    .collect(Collectors.toList());
            if (tcaElctrnNticSndngResultRepository.findById(tcaElctrnNticSndngResults.get(0).getElctrnNticSndngDetailId()).isPresent())
                tcaElctrnNticSndngResultRepository.modifyByElctrnNticSndngResults(tcaElctrnNticSndngResults);
            else
                tcaElctrnNticSndngResultRepository.saveAll(tcaElctrnNticSndngResults);

            responseVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build();
        } catch (EnsException e) {
            responseVO = EnsResponseVO.errBuilder()
                    .errCode(e.getErrCd())
                    .errMsg(e.getMessage())
                    .build();
        } catch (Exception e) {
            responseVO = EnsResponseVO.errBuilder()
                    .errCode(EnsErrCd.RSLT999)
                    .errMsg(String.format("[elctrnNticSndngId %s]에 대한 전송결과 FETCH 처리 실패. %s", elctrnNticSndngId, e.getMessage()))
                    .build();
        } finally {
            TcaElctrnNticSndng elctrnNticSndng = tcaElctrnNticSndngRepository.findById(elctrnNticSndngId).orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, "일치하는 tbInputXit 자료가 없습니다."));
            if (EnsErrCd.OK.equals(responseVO.getErrCode())) {
                elctrnNticSndng.setUpdate(FieldUpdate.builder()
                        .updusr("ENS_SYS")
                        .updtDt(LocalDateTime.now())
                        .build());
                elctrnNticSndng.setSndngProcessSttus(this.sndngProcessSttus(respDTO, elctrnNticSndng.getSndngProcessSttus()));
                elctrnNticSndng.setErrorCn(null);
            } else {
                elctrnNticSndng.setUpdate(FieldUpdate.builder()
                        .updusr("ENS_SYS")
                        .updtDt(LocalDateTime.now())
                        .build());
                elctrnNticSndng.setSndngProcessSttus(SndngProcessSttusCd.ensfail);
                elctrnNticSndng.setErrorCn(responseVO.getErrMsg());
            }
        }

        return responseVO;
    }

    private SndngProcessSttusCd sndngProcessSttus(IntgrnNotiRsltRespDTO respDTO, SndngProcessSttusCd sndngProcessSttus) {
        switch (respDTO.getStatCd()) {
            case accept:
                return sndngProcessSttus;
            case makefail:
            case sendfail:
                return SndngProcessSttusCd.ensfail;
            case makerdy:
            case making:
            case makeok:
                return SndngProcessSttusCd.ensmake;
            case sendrdy:
            case sending:
                return SndngProcessSttusCd.ensstart;
            case sendok:
            case sendcmplt:
                return SndngProcessSttusCd.ensok;
            case open:
                return SndngProcessSttusCd.ensopen;
            case close:
                return SndngProcessSttusCd.ensclose;
            default:
                return sndngProcessSttus;
        }
    }

    private SndngResultSttusCd sndngResultSttus(IntgrnDetailStatVO row) {
        return SndngResultSttusCd.valueOfEnum(row.getCurStatCd().getIntgrnDtlStatCd().getCode());
    }

}
