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.ElctrnNticSndngResult;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.embeded.FieldCreate;
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.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngResultRepository;
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.kkomydoc.model.KkoMydocRsltRespDTO;
import cokr.xit.ens.modules.kkomydoc.model.config.KkoMydocStat;
import cokr.xit.ens.modules.kkomydoc.service.KkoMydocService;
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 TrafficCcMydocFetcher implements EnsPhaseProcSupport<EnsResponseVO, String> {

    private final ElctrnNticSndngRepository elctrnNticSndngRepository;
    private final ElctrnNticSndngDetailRepository elctrnNticSndngDetailRepository;

    private final ElctrnNticSndngResultRepository elctrnNticSndngResultRepository;

    private final KkoMydocService kkoMydocService;


    /**
     * 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);

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


            EnsResponseVO apiRespVO = kkoMydocService.sendResultProvide(sendMastId);
            respDTO = (KkoMydocRsltRespDTO) apiRespVO.getResultInfo();


//            elctrnNticSndngResultRepository.saveAll(respDTO.getDocuments().stream()
//                    .map(row -> {
//                        return ElctrnNticSndngResult.builder()
//                                .elctrnNticSndngDetailId(elctrnNticSndngDetailRepository.findByExternalDocumentUuid(row.getExternalDocumentUuid())
//                                        .orElse(new ElctrnNticSndngDetail())
//                                        .getElctrnNticSndngDetailId())
//                                .sndngResultCode(this.sndngResultCode(row))
//                                .requstDt(row.getKkoDocSentDt())
//                                .inqireDt(row.getKkoDocReceivedDt())
//                                .readngDt(row.getKkoDocReadFrstDt())
//                                .errorCn(CmmnUtil.isEmpty(row.getErrorMessage()) ? null : row.getErrorMessage())
//                                .create(FieldCreate.builder()
//                                        .REGISTER("ENS_SYS")
//                                        .REGIST_DT(LocalDateTime.now())
//                                        .build())
//                                .build();
//                    })
//                    .collect(Collectors.toList())
//            );
            List<ElctrnNticSndngResult> elctrnNticSndngResults = respDTO.getDocuments().stream()
                    .map(row -> {
                        return ElctrnNticSndngResult.builder()
                                .elctrnNticSndngDetailId(elctrnNticSndngDetailRepository.findByExternalDocumentUuid(row.getExternalDocumentUuid())
                                        .orElse(new ElctrnNticSndngDetail())
                                        .getElctrnNticSndngDetailId())
                                .sndngResultCode(this.sndngResultCode(row))
                                .requstDt(row.getKkoDocSentDt())
                                .inqireDt(row.getKkoDocReceivedDt())
                                .readngDt(row.getKkoDocReadFrstDt())
                                .errorCn(CmmnUtil.isEmpty(row.getErrorMessage()) ? null : row.getErrorMessage())
                                .create(FieldCreate.builder()
                                        .register("ENS_SYS")
                                        .registDt(LocalDateTime.now())
                                        .build())
                                .build();
                    })
                    .collect(Collectors.toList());
            if (elctrnNticSndngResultRepository.findById(elctrnNticSndngResults.get(0).getElctrnNticSndngDetailId()).isPresent())
                elctrnNticSndngResultRepository.modifyByElctrnNticSndngResults(elctrnNticSndngResults);
            else
                elctrnNticSndngResultRepository.saveAll(elctrnNticSndngResults);

            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 {
            ElctrnNticSndng elctrnNticSndng = elctrnNticSndngRepository.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("99");
                elctrnNticSndng.setErrorCn(responseVO.getErrMsg());
            }
        }

        return responseVO;
    }

    private String sndngProcessSttus(KkoMydocRsltRespDTO respDTO, String sndngProcessSttus) {
       
        switch (respDTO.getStatCd()) {
            case makefail:
            case sendfail:
                return "99";   
            case sendok:
            case sendcmplt:
                return "02";   
            case open:
                return "08";   
            case close:
                return "09";   
            default:
                return sndngProcessSttus;
        }
    }

    private String sndngResultCode(KkoMydocStat row) {

       
        String sndngResultCode = null;
        try {
            switch (row.getKkoDocStat()) {
                case SENT:    
                case RECEIVED:
                case EXPIRED: 
                    sndngResultCode = "1"; 
                    break;
                case READ: 
                    sndngResultCode = "2"; 
                    break;
                case UNIDENTIFIED_USER:
                case FORBIDDEN:        
                case INVALID_VALUE:    
                case INTERNAL_ERROR:   
                case INVALID_REQUEST:  
                case INTERNAL_SENT_ERR:
                    sndngResultCode = "3"; 
                    break;
                default:
                    break;
            }
        } catch (Exception e) {
            log.info("IupSendSttusCd와 일치하는 값 없음. [ dataId {} KkoDocStat {} ]", row.getExternalDocumentUuid(), row.getKkoDocStat());
        }
        return sndngResultCode;
    }

}
