package com.brilliance.isc.common.limmod.service.impl;

import org.slf4j.LoggerFactory;
import org.slf4j.Logger;
import org.springframework.util.ObjectUtils;
import com.brilliance.isc.bo.Trn;
import com.brilliance.isc.common.api.bch.service.BchService;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.counter.service.CounterService;
import com.brilliance.isc.common.limmod.service.CecmExecute;
import com.brilliance.isc.common.limmod.service.LimCecmService;
import com.brilliance.isc.common.limmod.service.LimmodService;
import com.brilliance.isc.common.limmod.vo.LimmodVo;
import com.brilliance.isc.common.setmod.vo.SetmodVo;
import com.brilliance.isc.common.transaction.help.TransactionHelpService;
import com.brilliance.isc.common.trnmod.service.TrnmodService;
import com.brilliance.isc.esb.newmodel.cecm.*;
import com.brilliance.isc.mda.dao.*;
import com.brilliance.isc.utils.BigDecimalUtils;
import com.brilliance.isc.utils.DateUtils;
import com.brilliance.isc.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Service
public class LimCecmServiceImpl implements LimCecmService {

    private Map<String, CecmExecute> cecmExecutes = new HashMap<>();
    @Autowired
    private LimmodService limmodService;
    @Resource
    private TransactionHelpService transactionHelpService;
    @Resource
    private CecmopnMapper cecmopnMapper;
    @Resource
    private CecmameMapper cecmameMapper;
    @Resource
    private CecmsetMapper cecmsetMapper;
    @Resource
    private CecmclsMapper cecmclsMapper;
    @Resource
    private CecmudpMapper cecmudpMapper;
    @Resource
    private CecmfepMapper cecmfepMapper;
    @Resource
    private CecmengMapper cecmengMapper;
    @Resource
    private BattrnMapper battrnMapper;
    @Resource
    private CounterService counterService;
    @Autowired
    private BchService bchService;

    public static final Logger logger = LoggerFactory.getLogger(LimCecmServiceImpl.class);


    private ThreadLocal<LimmodVo> limmodVodata = ThreadLocal.withInitial(() -> {
        LimmodVo limmodVo1 = new LimmodVo();
        limmodVo1.reset();
        return limmodVo1;
    });


    @PostConstruct
    @Override
    public void initCecmService() {
        logger.info("----------------初始化cecm批量执行器");
        cecmExecutes.put("opn", new CecmExecute<Cecmopn>() {
            @Override
            public void relExecute(Cecmopn cecmopn, Trn trn) {
                cecmopn.setOpndat(DateUtils.parseDateToStr("yyyyMMdd", trn.getCpldattim()));
            }

            @Override
            public void savExecute() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmopn cecmOpn = (Cecmopn) limmodVo.getCecmBatchVo().getCecmmod();
                cecmOpn.setInr(counterService.dbCounterFormat("CECMOPN"));
                cecmOpn.setYwpz(limmodVo.getLim().getLimtyp());
                cecmOpn.setGhjgh(SettleContext.getUserSession().getOrgBch().getBranch());
                cecmOpn.setRzjgh(limmodVo.getLim().getBranch());
                cecmOpn.setEdlx(limmodVo.getLim().getLimtype());
                cecmOpn.setEdbh(limmodVo.getLim().getLimref());
                if (ObjectUtils.isEmpty(cecmOpn.getOwnref())) {
                    cecmOpn.setOwnref(limmodVo.getLim().getOwnref());
                }
                cecmOpn.setExtkey(limmodVo.getLim().getPtyextkey());
                cecmOpn.setKhnam(limmodVo.getLim().getPtynam());
                cecmOpn.setKlbz(limmodVo.getLimOccVo().BIZHON);
                cecmOpn.setKlje(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getLim().getComamt(), 6));

                if (!CollectionUtils.isEmpty(limmodVo.getLiaccvVo().getLiaccvg())) {
                    cecmOpn.setBzjzh(limmodVo.getLiaccvVo().getLiaccvg().get(0).getAcc());
                }
                if (ObjectUtils.isEmpty(cecmOpn.getBzjbl())) {
                    if (!ObjectUtils.isEmpty(limmodVo.getLiaccvVo().getCshpct())) {
                        cecmOpn.setBzjbl(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getLiaccvVo().getCshpct(), 6));
                    }
                }
                if (!ObjectUtils.isEmpty(limmodVo.getCbsMap().get("NOMAMT"))) {
                    cecmOpn.setKljerc(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getCbsMap().get("NOMAMT").getAmt(), 6));
                }
                cecmOpn.setFxfl(limmodVo.getLim().getFxfl());
                cecmOpn.setOpndat(limmodVo.getLim().getCredat());
                cecmOpn.setExpdat(limmodVo.getLim().getEnddat());

            }

            @Override
            public Cecmopn selectCecmmodInRelease(Trn trn) {
                return cecmopnMapper.selectByTrninr(trn.getInr());
            }

            @Override
            public void savetable() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmopn cecmopn = (Cecmopn) limmodVo.getCecmBatchVo().getCecmmod();
                if (ObjectUtils.isEmpty(cecmopnMapper.selectByPrimaryKey(cecmopn))) {
                    cecmopnMapper.insert(cecmopn);
                } else {
                    cecmopnMapper.updateByPrimaryKey(cecmopn);
                }
            }

            @Override
            public void deleteTable(Trn trn) {
                cecmopnMapper.deleteByTrninr(trn.getInr());
            }
        });
        cecmExecutes.put("ame", new CecmExecute<Cecmame>() {
            @Override
            public void relExecute(Cecmame cecmame, Trn trn) {

            }

            @Override
            public void savExecute() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmame cecmame = (Cecmame) limmodVo.getCecmBatchVo().getCecmmod();
                cecmame.setInr(counterService.dbCounterFormat("CECMAME"));
                cecmame.setOwnref(limmodVo.getOwnref());
                cecmame.setXgbz(limmodVo.getLimOccVo().BIZHON);
                cecmame.setXgje(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getLim().getComamt(), 6));
                cecmame.setBzjzh(limmodVo.getLiaccvVo().getLiaccvg().get(0).getAcc());
                cecmame.setTzhbzjbl(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getLiaccvVo().getCshpct(), 6));
                cecmame.setYxqdqr(limmodVo.getLim().getEnddat());
            }

            @Override
            public Cecmame selectCecmmodInRelease(Trn trn) {
                return cecmameMapper.selectByTrninr(trn.getInr());
            }

            @Override
            public void savetable() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmame cecmame = (Cecmame) limmodVo.getCecmBatchVo().getCecmmod();
                if (ObjectUtils.isEmpty(cecmameMapper.selectByPrimaryKey(cecmame))) {
                    cecmameMapper.insert(cecmame);
                } else {
                    cecmameMapper.updateByPrimaryKey(cecmame);
                }
            }

            @Override
            public void deleteTable(Trn trn) {
                cecmameMapper.deleteByTrninr(trn.getInr());
            }
        });
        cecmExecutes.put("set", new CecmExecute<Cecmset>() {
            @Override
            public void relExecute(Cecmset cecmset, Trn trn) {
                cecmset.setFkrq(DateUtils.parseDateToStr("yyyyMMdd", trn.getCpldattim()));
            }

            @Override
            public void savExecute() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmset cecmset = (Cecmset) limmodVo.getCecmBatchVo().getCecmmod();
                cecmset.setInr(counterService.dbCounterFormat("CECMSET"));
                cecmset.setOwnref(limmodVo.getOwnref());
                cecmset.setFkje(BigDecimalUtils.BigD2stringHalfUP(BigDecimalUtils.subtractAbs(limmodVo.getOldcomamt(), limmodVo.getComamt()), 6));
                cecmset.setXyzbdje(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getComamt(), 6));
                cecmset.setBzjfkje(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getCcvamt(), 6));

            }

            @Override
            public Cecmset selectCecmmodInRelease(Trn trn) {
                return cecmsetMapper.selectByTrninr(trn.getInr());
            }

            @Override
            public void savetable() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmset cecmset = (Cecmset) limmodVo.getCecmBatchVo().getCecmmod();
                if (ObjectUtils.isEmpty(cecmsetMapper.selectByPrimaryKey(cecmset))) {
                    cecmsetMapper.insert(cecmset);
                } else {
                    cecmsetMapper.updateByPrimaryKey(cecmset);
                }
            }

            @Override
            public void deleteTable(Trn trn) {
                cecmsetMapper.deleteByTrninr(trn.getInr());
            }

        });
        cecmExecutes.put("cls", new CecmExecute<Cecmcls>() {
            @Override
            public void relExecute(Cecmcls cecmod, Trn trn) {
                cecmod.setJqrq(DateUtils.parseDateToStr("yyyyMMdd", trn.getCpldattim()));
            }

            @Override
            public void savExecute() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmcls cecmcls = (Cecmcls) limmodVo.getCecmBatchVo().getCecmmod();
                cecmcls.setInr(counterService.dbCounterFormat("CECMCLS"));
                cecmcls.setOwnref(limmodVo.getOwnref());

            }

            @Override
            public Cecmcls selectCecmmodInRelease(Trn trn) {
                return cecmclsMapper.selectByTrninr(trn.getInr());
            }

            @Override
            public void savetable() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmcls cecmcls = (Cecmcls) limmodVo.getCecmBatchVo().getCecmmod();
                if (ObjectUtils.isEmpty(cecmclsMapper.selectByPrimaryKey(cecmcls))) {
                    cecmclsMapper.insert(cecmcls);
                } else {
                    cecmclsMapper.updateByPrimaryKey(cecmcls);
                }
            }

            @Override
            public void deleteTable(Trn trn) {
                cecmclsMapper.deleteByTrninr(trn.getInr());
            }
        });
        cecmExecutes.put("udp", new CecmExecute<Cecmudp>() {


            @Override
            public void relExecute(Cecmudp cecmod, Trn trn) {
                cecmod.setCdrq(DateUtils.parseDateToStr("yyyyMMdd", trn.getCpldattim()));
            }

            @Override
            public void savExecute() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmudp cecmudp = (Cecmudp) limmodVo.getCecmBatchVo().getCecmmod();
                cecmudp.setInr(counterService.dbCounterFormat("CECMENG"));
                cecmudp.setOwnref(limmodVo.getOwnref());
                cecmudp.setLdbh(limmodVo.getRec().getOwnref());
                cecmudp.setBdye(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getLim().getComamt(), 6));
                cecmudp.setCdje(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getLim().getComamt(), 6));
            }

            @Override
            public Cecmudp selectCecmmodInRelease(Trn trn) {
                return cecmudpMapper.selectByTrninr(trn.getInr());
            }

            @Override
            public void savetable() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmudp cecmudp = (Cecmudp) limmodVo.getCecmBatchVo().getCecmmod();
                if (ObjectUtils.isEmpty(cecmudpMapper.selectByPrimaryKey(cecmudp))) {
                    cecmudpMapper.insert(cecmudp);
                } else {
                    cecmudpMapper.updateByPrimaryKey(cecmudp);
                }
            }

            @Override
            public void deleteTable(Trn trn) {
                cecmudpMapper.deleteByTrninr(trn.getInr());
            }
        });
        cecmExecutes.put("eng", new CecmExecute<Cecmeng>() {


            @Override
            public void relExecute(Cecmeng cecmod, Trn trn) {

            }

            @Override
            public void savExecute() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmeng cecmmod = (Cecmeng) limmodVo.getCecmBatchVo().getCecmmod();
                cecmmod.setInr(counterService.dbCounterFormat("CECMENG"));
                cecmmod.setOwnref(limmodVo.getOwnref());
                cecmmod.setTzhbzjbl(BigDecimalUtils.BigD2stringHalfUP(limmodVo.getLiaccvVo().getCshpct(), 6));
                cecmmod.setBzjzh(limmodVo.getLiaccvVo().getLiaccvg().get(0).getAcc());
            }

            @Override
            public Cecmeng selectCecmmodInRelease(Trn trn) {
                return cecmengMapper.selectByTrninr(trn.getInr());
            }

            @Override
            public void savetable() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmeng cecmeng = (Cecmeng) limmodVo.getCecmBatchVo().getCecmmod();
                if (ObjectUtils.isEmpty(cecmengMapper.selectByPrimaryKey(cecmeng))) {
                    cecmengMapper.insert(cecmeng);
                } else {
                    cecmengMapper.updateByPrimaryKey(cecmeng);
                }
            }

            @Override
            public void deleteTable(Trn trn) {
                cecmudpMapper.deleteByTrninr(trn.getInr());
            }
        });
        cecmExecutes.put("fep", new CecmExecute<Cecmfep>() {

            @Override
            public void relExecute(Cecmfep cecmod, Trn trn) {
                cecmod.setFyfsrq(DateUtils.parseDateToStr("yyyyMMdd", trn.getCpldattim()));
            }

            @Override
            public void savExecute() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmfep cecmmod = (Cecmfep) limmodVo.getCecmBatchVo().getCecmmod();
                cecmmod.setInr(counterService.dbCounterFormat("CECMFEP"));
            }

            @Override
            public Cecmfep selectCecmmodInRelease(Trn trn) {
                return cecmfepMapper.selectByTrninr(trn.getInr());
            }

            @Override
            public void savetable() {
                LimmodVo limmodVo = limmodVodata.get();
                Cecmfep cecmfep = (Cecmfep) limmodVo.getCecmBatchVo().getCecmmod();
                if (ObjectUtils.isEmpty(cecmfepMapper.selectByPrimaryKey(cecmfep))) {
                    cecmfepMapper.insert(cecmfep);
                } else {
                    cecmfepMapper.updateByPrimaryKey(cecmfep);
                }
            }

            @Override
            public void deleteTable(Trn trn) {
                cecmfepMapper.deleteByTrninr(trn.getInr());
            }
        });
        logger.info("----------------初始化cecm批量执行器成功{}", cecmExecutes.toString());
    }

    /**
     * 保存cecm批量表 以及控制表
     *
     * @param limmodVo
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void saveCecm(LimmodVo limmodVo) {
        try {
            //收单行判断，如果是需要上收的交易，那么总行经办时直接返回，以免重复生成两条记录。
            if (bchService.isOrderBranchByFrm(SettleContext.getTransName())) {
                if ("2".equals(bchService.getStartFlgByBranchInifrm(limmodVo.getLim().getBranch(), SettleContext.getTransName()))) {
                    logger.info("cecm 批量处理 上收业务 以上收为准总行经办直接返回");
                    return;
                }
            }
            limmodVodata.remove();
            limmodVodata.set(limmodVo);
            //费用不用注册,在费用模块单独处理
            if (!"fep".equals(limmodVo.getCecmBatchVo().getBattrn().getObjtyp())) {
                limmodService.limRegister().cecmBuildData(limmodVo);
            }
            String objtyp = limmodVo.getCecmBatchVo().getBattrn().getObjtyp();
            if (StringUtils.isEmpty(objtyp)) {
                return;
            }
            logger.info("-------------------开始处理cecm 存表 类型为{}", objtyp);
            List<String> keys = cecmExecutes.keySet().stream().filter(key -> key.equals(objtyp)).collect(Collectors.toList());
            CecmExecute cecmExecute = cecmExecutes.get(keys.get(0));
            logger.info("正在给cecm{}组数", keys.get(0));
            cecmExecute.savExecute();
            Trn trn = transactionHelpService.getTransactionStoreSet().getTrnmodVo().getTrn();
            settingTransInfo(limmodVo.getCecmBatchVo().getBattrn(), trn, limmodVo.getCecmBatchVo().getCecmmod(), "W");
            cecmExecute.savetable();

            battrnMapper.insert(limmodVo.getCecmBatchVo().getBattrn());
            logger.info("cecm{}组数成功，trninr为{}", keys.get(0), trn.getInr());

        } catch (Exception ex) {
            logger.info("警告cecm批量提交处理失败{}", ex.getMessage());
        }

    }

    public void settingTransInfo(Battrn battrn, Trn trn, Cecmmod cecmmod, String sta) {
        if ("W".equals(sta)) {
            battrn.setCredat(DateUtils.dateTime());
            battrn.setSndtim(DateUtils.dateTimeNow());
            battrn.setSndsta("W");
            String inr = counterService.dbCounterFormat("BATTRN");
            battrn.setInr(inr);
            battrn.setObjinr(cecmmod.getInr());
            battrn.setTrninr(trn.getInr());
            cecmmod.setBattrninr(inr);
            cecmmod.setTrninr(trn.getInr());
        } else {
            battrn.setSndsta("R");
        }
    }

    /**
     * 回滚删除cecm数据
     *
     * @param trn
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void rollbackCecm(Trn trn) {
        try {
            logger.info("-------------------开始处理cecm 回滚 trninr为{}", trn.getInr());
            LimmodVo limmodVo = new LimmodVo();
            limmodVo.reset();
            CecmExecute cecmExecute = initExecut(trn, limmodVo);
            if (cecmExecute == null) {
                return;
            }
            battrnMapper.deleteByTrninr(trn.getInr());
            cecmExecute.deleteTable(trn);
        } catch (Exception ex) {
            logger.info("警告cecm批量回滚处理失败{}", ex.getMessage());
        }

    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public void releaseCecm(Trn trn) {
        try {
            logger.info("-------------------开始处理cecm 复核 trninr为{}", trn.getInr());
            LimmodVo limmodVo = new LimmodVo();
            limmodVo.reset();
            CecmExecute cecmExecute = initExecut(trn, limmodVo);
            if (cecmExecute == null) {
                return;
            }
            limmodVo.getCecmBatchVo().setCecmmod(cecmExecute.selectCecmmodInRelease(trn));
            cecmExecute.relExecute(limmodVo.getCecmBatchVo().getCecmmod(), trn);
            settingTransInfo(limmodVo.getCecmBatchVo().getBattrn(), trn, limmodVo.getCecmBatchVo().getCecmmod(), "R");
            cecmExecute.savetable();
            battrnMapper.updateByPrimaryKey(limmodVo.getCecmBatchVo().getBattrn());

        } catch (Exception ex) {
            logger.info("警告cecm批量复核处理失败{}", ex.getMessage());
        }
    }

    /**
     * 初始化批量执行器
     *
     * @param trn
     * @param limmodVo
     * @return
     */
    public CecmExecute initExecut(Trn trn, LimmodVo limmodVo) {
        limmodVodata.remove();
        limmodVodata.set(limmodVo);
        Battrn battrn = battrnMapper.selectByTrninr(trn.getInr());
        if (ObjectUtils.isEmpty(battrn)) {
            return null;
        }

        limmodVo.getCecmBatchVo().setBattrn(battrn);
        String objtyp = battrn.getObjtyp();

        if (StringUtils.isEmpty(objtyp)) {
            return null;
        }
        List<String> keys = cecmExecutes.keySet().stream().filter(key -> key.equals(objtyp)).collect(Collectors.toList());
        return cecmExecutes.get(keys.get(0));
    }
}
