package cokr.xit.ens.modules.common.ctgy.intgrnnoti.service.support;

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.ResultProcTemplate;
import cokr.xit.ens.modules.common.code.IntgrnDtlStatCd;
import cokr.xit.ens.modules.common.code.PostSeCd;
import cokr.xit.ens.modules.common.code.StatCd;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.code.TryStatCd;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendDetail;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.IntgrnSendMast;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendDetailRepository;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.domain.repository.IntgrnSendMastRepository;
import cokr.xit.ens.modules.common.ctgy.intgrnnoti.model.IntgrnDetailStatVO;
import cokr.xit.ens.modules.common.domain.support.FieldError;
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.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
@Component
@RequiredArgsConstructor
public class IntgrnNotiRsltFetcher extends ResultProcTemplate {

    private final IntgrnSendMastRepository intgrnSendMastRepository;
    private final IntgrnSendDetailRepository intgrnSendDetailRepository;

    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public EnsResponseVO execute(Long intSendMastId) {


        IntgrnSendMast intgrnSendMast = null;
        List<IntgrnSendDetail> sendDetails = null;
        EnsResponseVO respVO = null;
        Map<String, Long> resultInfo = new HashMap<>();
        resultInfo.put("intSendMastId", intSendMastId);
        try {
            if (CmmnUtil.isEmpty(intSendMastId))
                throw new EnsException(EnsErrCd.RSLT410, "발송마스터ID(은)는 필수조건 입니다.");

            intgrnSendMast = intgrnSendMastRepository.findById(intSendMastId).orElseThrow(() -> new EnsException(EnsErrCd.RSLT404, String.format("일치하는 발송마스터 자료가 없습니다. [ intSendMastId %s ]", intSendMastId)));


            List<IntgrnDetailStatVO> list = intgrnSendDetailRepository.findIntgrnDetailStatVOsByIntSendMastIdAndCurPostSe(intgrnSendMast.getIntSendMastId());

            intgrnSendDetailRepository.modifyDetailStatCdByIntgrnDetailStatVO(list);

            sendDetails = intgrnSendDetailRepository.findAllByIntgrnSendMast(intgrnSendMast);



            respVO = EnsResponseVO.okBuilder().resultInfo(resultInfo).build();
        } catch (EnsException e) {

            respVO = EnsResponseVO.errRsltBuilder().errCode(e.getErrCd()).errMsg(e.getMessage()).resultInfo(resultInfo).build();
        } catch (Exception e) {

            respVO = EnsResponseVO.errRsltBuilder().errCode(EnsErrCd.RSLT500).errMsg(e.getMessage()).resultInfo(resultInfo).build();
        } finally {
            if (!CmmnUtil.isEmpty(intgrnSendMast))
                if (EnsErrCd.OK.equals(respVO.getErrCode())) {
                    intgrnSendMast.setError(FieldError.initBuilder().build());


                    Integer readCnt = sendDetails.stream()
                            .map(row -> IntgrnDtlStatCd.READ.equals(row.getCurStatCd()) ? 1 : 0)
                            .reduce(Integer::sum)
                            .orElseGet(() -> 0);
                    intgrnSendMast.setReadCnt(readCnt);

                    if (StatCd.sendok.equals(intgrnSendMast.getStatCd())
                            || StatCd.sendcmplt.equals(intgrnSendMast.getStatCd())) {
                        if (readCnt > 0)
                            intgrnSendMast.setStatCd(StatCd.open);
                        else
                            intgrnSendMast.setStatCd(StatCd.sendcmplt);
                    } else if (StatCd.open.equals(intgrnSendMast.getStatCd())
                            || StatCd.close.equals(intgrnSendMast.getStatCd())) {
                    } else {
                        int sendOkCnt = 0;
                        int sendFailCnt = 0;


                        for (IntgrnSendDetail sendDetail : sendDetails) {
                            if (sendDetail.getCurStatCd().isSuccess())
                                sendOkCnt++;
                            else if (sendDetail.getCurStatCd().isFail())
                                sendFailCnt++;
                        }
                        if (sendOkCnt > 0)
                            intgrnSendMast.setStatCd(StatCd.sendok);
                        else if (sendFailCnt == sendDetails.size())
                            intgrnSendMast.setStatCd(StatCd.sendfail);
                        else
                            intgrnSendMast.setStatCd(StatCd.sending);
                    }
                } else {
                    intgrnSendMast.setError(FieldError.initBuilder()
                            .errorCode(respVO.getErrCode().getCode())
                            .errorMessage(respVO.getErrMsg())
                            .build());
                }



            if (!CmmnUtil.isEmpty(intgrnSendMast)) {

                this.tryStatCdToClosed(intgrnSendMast, sendDetails);

                if (TryStatCd.sndRsrv.equals(intgrnSendMast.getTryStatCd()) || TryStatCd.sndRtme.equals(intgrnSendMast.getTryStatCd())) {

                    PostSeCd postSeCd = intgrnSendMast.getTry1();
                    if (intgrnSendMast.getTrySeq() == 2) postSeCd = intgrnSendMast.getTry2();
                    else if (intgrnSendMast.getTrySeq() == 3) postSeCd = intgrnSendMast.getTry3();
                    int sendOkCnt = 0;
                    int sendFailCnt = 0;
                    int unknownCnt = 0;
                    int curPostTotCnt = 0;
                    for (IntgrnSendDetail sendDetail : sendDetails) {
                        if (!postSeCd.equals(sendDetail.getCurPostSe()))
                            continue;
                        curPostTotCnt++;


                        if (sendDetail.getCurStatCd().isSuccess())
                            sendOkCnt++;
                        else if (sendDetail.getCurStatCd().isFail())
                            sendFailCnt++;
                        else
                            unknownCnt++;

                    }
                    if (unknownCnt < curPostTotCnt)
                        if (sendOkCnt > 0)
                            intgrnSendMast.setTryStatCd(TryStatCd.ok);
                        else if (sendFailCnt == curPostTotCnt)
                            intgrnSendMast.setTryStatCd(TryStatCd.fail);


                }
            }
        }


        return respVO;
    }

    private void tryStatCdToClosed(IntgrnSendMast intgrnSendMast, List<IntgrnSendDetail> sendDetails) {
        if (TryStatCd.cmplt.equals(intgrnSendMast.getTryStatCd()))
            return;


        if (intgrnSendMast.getTrySeq() == intgrnSendMast.getTryCnt()
                && (TryStatCd.ok.equals(intgrnSendMast.getTryStatCd())
                || TryStatCd.fail.equals(intgrnSendMast.getTryStatCd())
                || StatCd.sendfail.equals(intgrnSendMast.getStatCd()))
        ) {
            intgrnSendMast.setTryStatCd(TryStatCd.cmplt);
            return;
        }


        int sendOkCnt = 0;
        for (IntgrnSendDetail sendDetail : sendDetails)
            if (sendDetail.getCurStatCd().isSuccess())
                sendOkCnt++;
        if (sendDetails.size() == sendOkCnt)
            intgrnSendMast.setTryStatCd(TryStatCd.cmplt);

    }


}
