package cokr.xit.ens.biz.iup.signtalk.service;

import cokr.xit.ens.biz.iup.code.IupPrcsCd;
import cokr.xit.ens.biz.iup.code.IupSendTypeCd;
import cokr.xit.ens.biz.iup.domain.TbInputXit;
import cokr.xit.ens.biz.iup.domain.repository.TbInputXitRepository;
import cokr.xit.ens.biz.iup.signtalk.service.support.IupSigntalkAcceptor;
import cokr.xit.ens.biz.iup.signtalk.service.support.IupSigntalkFetcher;
import cokr.xit.ens.biz.iup.signtalk.service.support.IupSigntalkSender;
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.ctgy.intgrnnoti.service.event.IntgrnNotiSendReserveEvent;
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
public class IupSigntalkService {


    private final TbInputXitRepository tbInputXitRepository;

    private final IupSigntalkAcceptor iupSigntalkAcceptor;
    private final IupSigntalkSender iupSigntalkSender;
    private final IupSigntalkFetcher iupSigntalkFetcher;

    private final ApplicationEventPublisher applicationEventPublisher;


    /**
     * 인증톡 접수(IUP -> ENS)
     */
    @Transactional
    public EnsResponseVO accept(Long lnkInputId) {

        try {
           
            TbInputXit tbInputXit = tbInputXitRepository.findByPrcsCdAndSendTypeAndId(IupPrcsCd.TGRG, IupSendTypeCd.KP, lnkInputId)
                    .orElseThrow(() -> new EnsException(EnsErrCd.ACPT404, "일치하는 자료가 없거나 \"등록(TGRG)\" 상태가 아닙니다."));

            return this.accept(Arrays.asList(tbInputXit)).getResultInfo().get(0);
        } catch (EnsException e) {
            return EnsResponseVO.errBuilder()
                    .errCode(e.getErrCd())
                    .errMsg(e.getMessage())
                    .build();
        }
    }

    /**
     * 인증톡 접수(IUP -> ENS)
     */
    @Transactional
    public EnsResponseVO<List<EnsResponseVO>> acceptAll() {
        try {
           
            List<TbInputXit> tbInputXits = tbInputXitRepository.findAllByPrcsCdInAndSendType(Arrays.asList(IupPrcsCd.TGRG), IupSendTypeCd.KP);
            if (CmmnUtil.isEmpty(tbInputXits))
                throw new EnsException(EnsErrCd.ACPT404, "\"등록(TGRG)\" 상태의 자료가 없습니다.");

            return this.accept(tbInputXits);
        } catch (EnsException e) {
            return EnsResponseVO.<List<EnsResponseVO>>errBuilder()
                    .errCode(e.getErrCd())
                    .errMsg(e.getMessage())
                    .build();
        }
    }

    private EnsResponseVO<List<EnsResponseVO>> accept(List<TbInputXit> tbInputXits) {
        iupSigntalkAcceptor.statReady(tbInputXits.stream().map(row -> row.getLnkInputId()).collect(Collectors.toList()));

        List<EnsResponseVO> resultInfo = tbInputXits.stream()
                .map(row -> iupSigntalkAcceptor.execute(row.getLnkInputId()))
                .collect(Collectors.toList());


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

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

//    /**
//     * 인증톡 제작 재요청
//     * @param lnkInputId
//     * @return
//     */
//    public EnsResponseVO reMake(Long lnkInputId){
//        return iupSigntalkMaker.execute(lnkInputId);
//    }


    /**
     * 인증톡 전송 재요청
     *
     * @param lnkInputId
     * @return
     */
    public EnsResponseVO reSend(Long lnkInputId) {
        return iupSigntalkSender.execute(lnkInputId);
    }


    /**
     * 인증톡 전송(성공/실패) 결과 가져오기
     */
    @Transactional
    public EnsResponseVO fetch(Long lnkInputId) {
        TbInputXit tbInputXit = null;
        try {
            tbInputXit = tbInputXitRepository.findById(lnkInputId)
                    .orElseThrow(() -> new EnsException(EnsErrCd.ERR404, String.format("[ lnkInputId %s ]와 일치하는 자료가 없습니다.", lnkInputId)));
            if (!IupSendTypeCd.KP.equals(tbInputXit.getSendType()))
                new EnsException(EnsErrCd.ERR404, String.format("[ lnkInputId %s ]는 인증톡 자료가 아닙니다.", lnkInputId));
        } catch (EnsException e) {
            return EnsResponseVO.errBuilder()
                    .errCode(e.getErrCd())
                    .errMsg(e.getMessage())
                    .build();
        }

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

    /**
     * 인증톡 전송(성공/실패) 결과 모두 가져오기
     */
    public EnsResponseVO fetchAll() {
        List<TbInputXit> tbInputXits = tbInputXitRepository.findAllByPrcsCdInAndSendType(Arrays.asList(IupPrcsCd.TGRC, IupPrcsCd.CICV, IupPrcsCd.CICC, IupPrcsCd.COMP, IupPrcsCd.INCM), IupSendTypeCd.KP);

        return this.fetch(tbInputXits);
    }

    private EnsResponseVO fetch(List<TbInputXit> tbInputXits) {
        iupSigntalkFetcher.statReady(tbInputXits.stream().map(row -> row.getLnkInputId()).collect(Collectors.toList()));

        return EnsResponseVO.okBuilder()
                .resultInfo(
                        tbInputXits.stream()
                                .map(row -> iupSigntalkFetcher.execute(row.getLnkInputId()))
                                .collect(Collectors.toList()
                                )
                )
                .build();
    }


}
