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

import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.ElctrnNticSndng;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.domain.repository.ElctrnNticSndngRepository;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support.TrafficCcMydocAcceptor;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support.TrafficCcMydocFetcher;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support.TrafficCcMydocMaker;
import cokr.xit.ens.biz.traffic.chuncheon.mydoc.v2.service.support.TrafficCcMydocSender;
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.kkomydoc.service.event.KkoMydocSendReserveEvent;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
@RequiredArgsConstructor
@Transactional
public class TrafficCcMydocService {

    private final ElctrnNticSndngRepository elctrnNticSndngRepository;

    private final TrafficCcMydocAcceptor trafficCcMydocAcceptor;
    private final TrafficCcMydocMaker trafficCcMydocMaker;
    private final TrafficCcMydocSender trafficCcMydocSender;
    private final TrafficCcMydocFetcher trafficCcMydocFetcher;

    private final ApplicationEventPublisher applicationEventPublisher;



    /**
     * 인증톡 접수(TRAFFIC -> ENS)
     */
    public EnsResponseVO accept(String elctrnNticSndngId){

        try {
           
            ElctrnNticSndng elctrnNticSndng = elctrnNticSndngRepository.findById(elctrnNticSndngId)
                    .orElseThrow(()->new EnsException(EnsErrCd.ACPT404, "일치하는 자료가 없거나 \"요청(01)\" 상태가 아닙니다."));

            return this.accept(Arrays.asList(elctrnNticSndng)).getResultInfo().get(0);
        } catch (EnsException e){
            return EnsResponseVO.errBuilder()
                    .errCode(e.getErrCd())
                    .errMsg(e.getMessage())
                    .build();
        }
    }
    /**
     * 인증톡 접수(TRAFFIC -> ENS)
     */
    public EnsResponseVO<List<EnsResponseVO>> acceptAll(){
        try {
           
            List<ElctrnNticSndng> elctrnNticSndngs = elctrnNticSndngRepository.findAllBySndngProcessSttus("01");
            if(CmmnUtil.isEmpty(elctrnNticSndngs))
                throw new EnsException(EnsErrCd.ACPT404, "\"요청(01)\" 상태의 자료가 없습니다.");

            return this.accept(elctrnNticSndngs);
        } catch (EnsException e){
            return EnsResponseVO.<List<EnsResponseVO>>errBuilder()
                    .errCode(e.getErrCd())
                    .errMsg(e.getMessage())
                    .build();
        }
    }
    private EnsResponseVO<List<EnsResponseVO>> accept(List<ElctrnNticSndng> elctrnNticSndngs){
        EnsResponseVO responseVO = trafficCcMydocAcceptor.statReady(elctrnNticSndngs.stream()
                .map(row -> row.getElctrnNticSndngId())
                .collect(Collectors.toList()));
        if(!EnsErrCd.OK.equals(responseVO.getErrCode()))
            return responseVO;

        List<EnsResponseVO> resultInfo = elctrnNticSndngs.stream()
                .map(row -> trafficCcMydocAcceptor.execute(row.getElctrnNticSndngId()))
                .collect(Collectors.toList());


        List<Long> sendMastIds = resultInfo.stream()
                .filter(ensResponseVO -> EnsErrCd.OK.equals(ensResponseVO.getErrCode()))
                .map(ensResponseVO -> (Long)((Map<String, Object>)ensResponseVO.getResultInfo()).get("sendMastId"))
                .collect(Collectors.toList());
        KkoMydocSendReserveEvent event = KkoMydocSendReserveEvent.builder()
                .sendMastIds(sendMastIds)
                .callback(() -> this.fetch(elctrnNticSndngs))
                .build();
        applicationEventPublisher.publishEvent(event);

        return EnsResponseVO.<List<EnsResponseVO>>okBuilder().resultInfo(resultInfo).build();
    }





    /**
     * 인증톡 제작 재요청
     * @param elctrnNticSndngId
     * @return
     */
    public EnsResponseVO reMake(String elctrnNticSndngId){
        return trafficCcMydocMaker.execute(elctrnNticSndngId);
    }


    /**
     * 인증톡 전송 재요청
     * @param elctrnNticSndngId
     * @return
     */
    public EnsResponseVO reSend(String elctrnNticSndngId){
        return trafficCcMydocSender.execute(elctrnNticSndngId);
    }


    /**
     * 인증톡 전송(성공/실패) 결과 가져오기
     */
    public EnsResponseVO fetch(String elctrnNticSndngId){
        ElctrnNticSndng elctrnNticSndng = null;
        try {
            elctrnNticSndng = elctrnNticSndngRepository.findById(elctrnNticSndngId)
                    .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("[ elctrnNticSndngId %s ]와 일치하는 자료가 없습니다.", elctrnNticSndngId)));
        } catch (EnsException e) {
            return EnsResponseVO.errBuilder()
                    .errCode(e.getErrCd())
                    .errMsg(e.getMessage())
                    .build();
        }

        return this.fetch(Arrays.asList(elctrnNticSndng));
    }

    /**
     * 인증톡 전송(성공/실패) 결과 모두 가져오기
     */
    public EnsResponseVO fetchAll(){
        List<ElctrnNticSndng> elctrnNticSndngs = elctrnNticSndngRepository.findAllBySndngProcessSttusIn(Arrays.asList("02", "08"));

        return this.fetch(elctrnNticSndngs);
    }

    private EnsResponseVO fetch(List<ElctrnNticSndng> elctrnNticSndngs){

        return EnsResponseVO.okBuilder()
                .resultInfo(
                        elctrnNticSndngs.stream()
                                .map(row -> trafficCcMydocFetcher.execute(row.getElctrnNticSndngId()))
                                .collect(Collectors.toList()
                                )
                )
                .build();
    }


}
