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

import com.brilliance.mda.runtime.mda.util.Dates;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.brilliance.mda.runtime.mda.util.Streams;
import com.brilliance.isc.bo.Bch;
import com.brilliance.isc.bo.Pbl;
import com.brilliance.isc.common.bop.service.IPblStoreContract;
import com.brilliance.isc.common.bop.service.PblmodService;
import com.brilliance.isc.common.component.DyncDaoService;
import com.brilliance.isc.common.context.BopContext;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.context.SpringEnvContext;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.rmbbop.common.*;
import com.brilliance.isc.common.sysmod.SysmodService;
import com.brilliance.isc.common.transaction.help.TransactionHelpService;
import com.brilliance.isc.common.util.RmbbopUtils;
import com.brilliance.isc.common.util.Utils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Date;
import java.util.List;
import java.util.Optional;

@Service
public class PblmodServiceImpl implements PblmodService {

    @Autowired
    private DyncDaoService dyncDaoService;

    @Autowired
    private SysmodService sysmodService;

    @Autowired
    private TransactionHelpService transactionHelpService;

    @Override
    public void storeAllinBusTx(AbstractRmb abstractRmb) {
        // 业务交易中使用
        //增加调用savdatafrompanel逻辑，在退回后经办删除多余的子节点表数据
//        IPblStoreContract pblStoreContract = SpringEnvContext.getBean(iPblData.getObjtyp());
//        pblStoreContract.buildData(iPblData);
//        iPblData.getPblmod().setDectyp("V");
        setPblSta(abstractRmb);
        rmbStoreContract(abstractRmb);
        setPblData(abstractRmb); //设置交易存盘状态
        rmbStorePBL(abstractRmb);

    }

    @Override
    public void setPblSta(AbstractRmb abstractRmb) {
        //!设置交易状态
        setRmbDectyp(abstractRmb);
        //!设置控制表PBL的状态
        // 这段逻辑，RMBSetPBLStatus用到PBL\\TMPSAV来判断，但是SetModuleContent( PBL, WRKPBL )不是已经覆盖了吗？
        // 这函数的逻辑，应该是根据WRKPBL\\STA（旧的状态）设置PBL\\STA的状态，并将WRKPBL和PBL的内容设置成一致
//        Pbl wrkPbl = iPblData.getPblmod().getWrkpbl();
        rmbSetPBLStatus(abstractRmb);
        // 这两个字段的值是不同的
        Pblmod pblmod = abstractRmb.getPblmod();
        pblmod.getWrkpbl().setSta(pblmod.getPbl().getSta());
        pblmod.getWrkpbl().setTmpsav(pblmod.getPbl().getTmpsav());
        if (dyncDaoService.dyncReadNoDataByInr(pblmod.getWrkpbl())) {
            BeanUtils.copyProperties(pblmod.getWrkpbl(), pblmod.getPbl());
        }

    }

    @Override
    public void rmbStoreContract(AbstractRmb abstractRmb) {
        //!向数据库中存储RMB对象的数据
        //!===================================
        //!返回值: 无
        //!变量：Obj  RMB对象数据
        //!===================================
        //! 存储ADS数据
//        PblInfo pblInfo = iPblData.getPblmod().getPblInfo();
//        String objInr = pblInfo.getObjinr();
//        String objtyp = pblInfo.getObjtyp();
        // Retrieve full qualified path of passed module
        //String objPath = MdaDriver.getModuleInfo(obj,tdModuleInfoFullName);
        Object objRec = abstractRmb.getRecgrp().getAds();
        savBankTraNo(abstractRmb);

        if (dyncDaoService.dyncReadNoDataByInr(objRec)) {
            sysmodService.sdbUpdateWithLog(objRec);
        } else {
            sysmodService.sdbInsertWithLog(objRec);
        }
        String objtyp = abstractRmb.getObjtyp().toLowerCase();
        IPblStoreContract<AbstractRmb> pblStoreContract = SpringEnvContext.getBean(objtyp);
        pblStoreContract.saveChildData(abstractRmb);
    }


    public void savBankTraNo(AbstractRmb abstractRmb) {
        //!存盘时存储业务编号
        //!===================================
        //!返回值：无
        //!===================================
        String ownref = abstractRmb.getPblmod().getPblInfo().getOwnref();
        String banktrano = Utils.getFieldValue(abstractRmb.getRecgrp().getAds(), "banktrano", "");
        if (!MdaUtils.isEmpty(ownref) && MdaUtils.isEmpty(banktrano)) {
            Utils.setFieldValue(abstractRmb.getRecgrp().getAds(), "banktrano", ownref);
        }

    }

    public Object getNewInstance(Object obj) {
        try {
            return obj.getClass().newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
        return null;
    }

    public boolean isRCPMISModule(AbstractRmb abstractRmb) {
        /**
         $frame = GetFramename
         select case $frame
         case "LITOPN", "BRTUDP", "BPTOPN", "BETSND", "BETACC", "LTTOPN", "BTTACC", "BTTSND"
         return TRUE
         case else
         return FALSE
         end select
         **/
        if (MdaUtils.compareTo(abstractRmb.getPblmod().getDectyp(), "V") == 0) {
            switch (abstractRmb.getPblmod().getPblInfo().getObjtyp()) {
                case "TDN":
                case "TEJ":
                case "TEK":
                case "TDA":
                case "TFB":
                case "TDM":
                case "TDF":
                case "TDB":
                case "TCR":
                case "TDO":
                case "TDQ":
                case "TBK":
                case "TBZ":
                    return true;
                default:
                    return false;
            }
        } else {
            return false;
        }

    }

    @Override
    public void setPblData(AbstractRmb abstractRmb) {
        //!设置信息状态表PBL的数据
        //!===================================
        //!变量：  path    pancel存取路径
        //!        objtyp  处理的对象名
        //!===================================
        IRecgrp recgrp = abstractRmb.getRecgrp();
        String objtyp = abstractRmb.getObjtyp();
        String objinr = recgrp.getAds().getInr();
        String trninr = transactionHelpService.getTrninr();
        abstractRmb.getPblmod().getPbl().setTrninr(trninr);
        abstractRmb.getPblmod().getPbl().setObjtyp(objtyp);
        abstractRmb.getPblmod().getPbl().setObjinr(objinr);
        abstractRmb.getPblmod().getPbl().setLevyno(recgrp.getAds().getLevyno());
        abstractRmb.getPblmod().getPbl().setOwnusr(SettleContext.getUserSession().getUsr().getExtkey());
        abstractRmb.getPblmod().getPbl().setOwnextkey(recgrp.getAds().getOwnextkey());
        setPBLAdsCSta(abstractRmb);
        if (MdaUtils.compareTo(abstractRmb.getPblmod().getDectyp(), "V") == 0) {
            abstractRmb.getPblmod().getPbl().setRelflg("W");
        } else {
            abstractRmb.getPblmod().getPbl().setRelflg("R");
        }
        if (MdaUtils.isEmpty(abstractRmb.getPblmod().getPbl().getCredat())) {
            abstractRmb.getPblmod().getPbl().setCredat(getCoreSysDay());
        }
        // 原注释：在提取交易中生成申报号码时，要同时设日期定入帐
//        if (MdaUtils.compareTo(iRmb.getPblmod().getDectyp(), "V") == 0 && MdaUtils.isEmpty(iRmb.getPblmod().getPbl().getReldat())) {
        // 业务交易，界面无此字段，这个日期要和申报编号对应，不能随便改
        abstractRmb.getPblmod().getPbl().setReldat(getCoreSysDay());
//        }

    }

    @Override
    public void rmbStorePBL(AbstractRmb abstractRmb) {

        //!保存当前PBL信息
//        String objFlg = "";
//        if (!MdaUtils.isEmpty(iPblData.getPblmod().getPbl().getInr())) {
//            boolean isExist = dyncDaoService.dyncReadNoDataByInr(iPblData.getPblmod().getPbl());
//            if (isExist) {
//                objFlg = "F";
//            }
//        }
//
//        if (MdaUtils.isEmpty(objFlg)) {
        sysmodService.sdbInsertWithLog(abstractRmb.getPblmod().getPbl());

//        } else {
//            sysmodService.sdbUpdateWithLog(iPblData.getPblmod().getPbl());
//        }

    }

    @Override
    public void unbunding(AbstractRmb abstractRmb) {
        Pblmod pblmod = abstractRmb.getPblmod();
        String dectyp = pblmod.getDectyp();
        if ("M".equals(dectyp) || "D".equals(dectyp)) {
            Pbl wrkpbl = pblmod.getWrkpbl();
            if (dyncDaoService.dyncReadNoDataByInr(wrkpbl)) {
                wrkpbl = (Pbl) sysmodService.sdbRead(wrkpbl);
                wrkpbl.setSta("G");
                wrkpbl.setRelflg("X");
                sysmodService.sdbUpdateWithLog(wrkpbl);
            }
        }
    }

    private void setPBLAdsCSta(AbstractRmb abstractRmb) {

        // 更新主报文数据状态
        String actiontype = abstractRmb.getRecgrp().getAds().getOpertype();
        abstractRmb.getPblmod().getPbl().setAdscsta(genCsta(actiontype));

    }

    /**
     * source:pblmod.0055.script
     */
    public String genCsta(String argoprtyp) {
        //!根据操作类型生成数据状态
        // 1-有效（操作类型为新增/变更）
        // 0-作废（操作类型为撤销）
        String rc = "";
        if (StringUtils.isNotEmpty(argoprtyp)) {
            if (StringUtils.equals(argoprtyp, "1") || StringUtils.equals(argoprtyp, "2")) {
                rc = "1";
            } else {
                if (StringUtils.equals(argoprtyp, "3")) {
                    rc = "0";
                }
            }
        }
        return rc;

    }

    //TODO 读取加载CoreSysDay的逻辑
    public Date getCoreSysDay() {
        return Dates.today();
    }

    private void rmbSetPBLStatus(AbstractRmb rmb) {
        // 将输入参数去掉
        IRecgrp recgrp = rmb.getRecgrp();
        String actiontype = recgrp.getAds().getOpertype();
        Pblmod pblmod = rmb.getPblmod();
        String pblsta = pblmod.getWrkpbl().getSta();
        if (StringUtils.isNotEmpty(pblmod.getPbl().getTmpsav())) {
            pblsta = "Z";
        } else {
            switch (pblmod.getDectyp()) {
                case "A": //新增
                case "V": //提取
                    pblsta = "0";
                    break;
                case "M": //修改
                    Rmbbut rmbbut = rmb.getRmbbut();
                    if ("X".equals(rmbbut.getFlg())) {
                        pblsta = "0";
                    }
                    break;
                case "D": //删除
//                    if (!"D".equals(pblmod.getWrkpbl().getSta() )) {
                    switch (actiontype) {
                        //当状态是wait的时候如果删除就是彻底删除
                        case "1":
                            // 勾选主信息确认
//                            String acp = pblmod.getPblInfo().getAcp();
//                            if (StringUtils.isNotEmpty(acp)) {
                            pblsta = "G";
//                            }
                            break;
                        case "2":
                        case "3":
                            pblsta = "0";
                            //当状态是snd的时候再删除就是DELETE状态，然后再次发送
                            break;
                    }
//                    }
                    break;
            }
        }
        pblmod.getPbl().setSta(pblsta);

    }

    public void rmbLoadDataWithDBL(String dblinr, AbstractRmb abstractRmb) {
        //取得上下文
        //!根据WRKPBL中的信息读入对应的RMB对象的数据并将该数据加锁
        //!===================================
        //!返回值: 无
        //!变量:   dblinr  WRKPBL INR
        //!        objmodule  对应RMB模块
        //!===================================
        //!处理流程如下:
        //!1.重置交易状态
        setRmbDectyp(abstractRmb);
        //!1.5.读入对应DBL数据

        boolean exist = dyncDaoService.dyncReadByInr(abstractRmb.getPblmod().getWrkpbl(), dblinr);
        if (!exist) {
            throw new CommonServiceException("无法读取数据" + dblinr);
        }
        //!2.try to lock pbl  TODO 需要对此读的数据加锁
        if (!exist) {
            throw new CommonServiceException("无法锁定数据" + dblinr);
        }
        // 这两个模块一个用于读数据库的（旧数据），一个用于保存（新数据），初始化时应该设置为一样
        BeanUtils.copyProperties(abstractRmb.getPblmod().getWrkpbl(), abstractRmb.getPblmod().getPbl());


        //!4.读入对应的业务数据
        Utils.setFieldValue(getNewInstance(abstractRmb.getRecgrp().getAds()), "inr", abstractRmb.getPblmod().getWrkpbl().getObjinr());
        rmbLoadContract(abstractRmb);

    }

    private void setRmbDectyp(AbstractRmb abstractRmb) {
        Pblmod pblmod = abstractRmb.getPblmod();
        if (StringUtils.isEmpty(pblmod.getDectyp())) {
            String transName = SettleContext.getTransName();
            if (!transName.startsWith(abstractRmb.getObjtyp().toUpperCase())) {
                pblmod.setDectyp("V"); //!V数据提取交易
            } else {
                switch (StringUtils.substring(transName, 3, 6)) {
                    case "ADD": //!A增加
                        pblmod.setDectyp("A");
                        break;
                    case "AME": //!M修改
                        pblmod.setDectyp("M");
                        break;
                    case "DEL": //!D删除
                        pblmod.setDectyp("D");
                        break;
                    case "SND": //!S发送
                        pblmod.setDectyp("S");
                        break;
                    case "INF":
                    case "PNT":      //!I查询/打印不用区分，其实也没有打印交易
                        pblmod.setDectyp("I");
                        break;
                }
            }
        }
    }

    public void rmbLoadContract(AbstractRmb abstractRmb) {

        //!读入对应的RMB对象的数据并将该数据加锁
        //!===================================
        //!返回值: 无
        //!变量:   Obj  RMB对象MODULE
        //!===================================
        //!处理步骤如下:
        PblInfo pblInfo = abstractRmb.getPblmod().getPblInfo();
        String objInr = pblInfo.getObjinr();
        String objTyp = pblInfo.getObjtyp();
        String notFndTxt = "";
        if (MdaUtils.isEmpty(objInr)) {
            notFndTxt = MdaUtils.getI18NString("pblmod", "CT000007");
            return;
        }


        String ownref = abstractRmb.getPblmod().getWrkpbl().getLevyno();

        Object objRec = abstractRmb.getRecgrp().getAds();
        //!1.读入BAS数据
        if (MdaUtils.compareTo(abstractRmb.getPblmod().getDectyp(), "I") == 0) {
            boolean exist = dyncDaoService.dyncReadByInr(objRec, objInr);
            if (!exist) {
                throw new CommonServiceException("无法读取数据" + objTyp + objInr);
            }
        } else {
            //TODO  需要对此读的数据加锁
            boolean exist = dyncDaoService.dyncReadByInr(objRec, objInr);
            if (!exist) {
                throw new CommonServiceException("无法锁定数据" + objTyp + objInr + ownref);
            }
        }

        IPblStoreContract pblStoreContract = SpringEnvContext.getBean(objTyp);
        if (pblStoreContract != null) {
            pblStoreContract.rmbLoadContract(abstractRmb);
        }

        //!3.将对应的OPERTYPE作为旧数据缓存到STREAM中
        setRMBPresaveoldValue(abstractRmb);
    }

    public void setRMBPresaveoldValue(AbstractRmb abstractRmb) {

        //取得上下文
        //!进入交易时保存旧有的OPERTYPE数据
        //!----以后可以客户化保存其他需要保存的数据
        //!===================================
        //!返回值：无
        //!变量：  OBJ  对应的模块实例
        //!===================================
        String objTyp = abstractRmb.getPblmod().getPblInfo().getObjtyp();
        /**
         $path = RMBGetPath( obj, "ADS" ) + "\\\\OPERTYPE"
         $value = GetContent( $path )
         **/
        String value = abstractRmb.getPblmod().getPblInfo().getOpertype();

        Streams.streamInsert(abstractRmb.getPblmod().getOldvalstm(), 0, "ADS_OPERTYPE" + "\t" + value);

        IPblStoreContract pblStoreContract = SpringEnvContext.getBean(objTyp);
        if (pblStoreContract != null) {
            List<String> list = pblStoreContract.setRMBPresaveoldValue(abstractRmb);
            abstractRmb.getPblmod().getOldvalstm().getRows().addAll(list);
        }
    }

    /**
     * 公共映射方法
     *
     * @param abstractRmb IPblData
     */
    @Override
    public void mappingRMBDataCommon(AbstractRmb abstractRmb) {
        //相同逻辑字段的映射，如业务编号
        //此函数只能使用全局可见的函数和字段
        IRecgrp recgrp = abstractRmb.getRecgrp();

        //银行业务编号
//        $mod = GetModule( "\\MTABUT\\REC" )
//        if ErrorCode = 0 then
//        $path = RecGetPath( $mod )
        String ownref = BopContext.getBizInfo().getOwnref();
        String rmbownref = Utils.getFieldValue(recgrp.getAds(), "banktrano");

//        if not IsEmpty( $lodflg ) then
//        if $lodflg = "N" then
//        if not IsEmpty( $ownref ) and $ownref <> $rmbownref then
//        MappingFieldByPath( RMBPATH + "\\RECGRP\\ADS\\BANKTRANO", $ownref )
//        $LEVYNO = GetRmbRef
//        else
//        $rmblevynopath = RMBPATH + "\\RECGRP\\ADS\\LEVYNO"
//        $LEVYNO = GetContentN( $rmblevynopath )
//        endif
//        endif
//        else
        if (StringUtils.isNotEmpty(ownref) && !StringUtils.equals(ownref, rmbownref)) {
            Utils.setFieldValue(recgrp.getAds(), "banktrano", ownref);
            //Rmb2112取Rmb2101的业务主键，试算时不赋值
            String levyno = recgrp.getAds().getLevyno();
            if (StringUtils.isEmpty(levyno) && !StringUtils.equals(abstractRmb.getObjtyp(), "TCR")) {
                Utils.setFieldValue(recgrp.getAds(), "levyno", RmbbopUtils.getRmbRef(abstractRmb));
            }
        }
//        endif
//        endif

//        if DECTYP = "V" and RMBPATH = "\RMBBOP\RMB2112\RECP" then
        //业务主键
//        Post( "exeDefault(\"RMB2112\RECGRP\ADS\LEVYNO\" ) ", 1 )
//        $err = ErrorCode
//        else
//        MappingFieldByPath( RMBPATH + "\\RECGRP\\ADS\\LEVYNO", $LEVYNO )
//        endif
        //操作类型
        Utils.setFieldValue(recgrp.getAds(), "opertype", "1");
        //银行机构代码
        Utils.setFieldValue(recgrp.getAds(), "bankorgcode", RmbbopUtils.getLhanum());
        Utils.setFieldValue(recgrp.getAds(), "leorgcode", RmbbopUtils.getLhanum());
        //业务所属机构
        Bch wrkbch = Optional.ofNullable(SettleContext.getUserSession().getWrkbch()).orElseGet(Bch::new);
        Bch bch = Optional.ofNullable(SettleContext.getUserSession().getBch()).orElseGet(Bch::new);
        String ownextkey = StringUtils.isEmpty(wrkbch.getBranch()) ? bch.getBranch() : wrkbch.getBranch();
        Utils.setFieldValue(recgrp.getAds(), "ownextkey", ownextkey);
    }

    @Override
    public <T> void setListData(Pblmod pblmod, List<T> listData) {
        //更新节点明细表中的状态，数据状态
        //listtbl与listpanel一一对应时使用
        //arglsttblpth - 节点表listpath
        //argPanellistPath - 节点panel listpath
        //eg:2106/tej- ("\\RECGRP\\TEJ","\\TEJPP")
        for (Object obj : listData) {
            String listopertype = Utils.getFieldValue(obj, "listopertype");
            //勾选确认
            String acp = (String) Utils.getField(obj, "acp").orElseGet(String::new);
            if (StringUtils.isNotEmpty(acp)) {
                String sta = rmbSetListStatus(pblmod.getDectyp(), listopertype);
                Utils.setFieldValue(obj, "sta", sta);
                //更新数据状态
                Utils.setFieldValue(obj, "csta", genCsta(listopertype));
            }
        }
    }

    public String rmbSetListStatus(String dectyp, String listopertype) {
        //根据操作类型设置节点状态
        switch (dectyp) {
            case "V":
            case "A":
                if (StringUtils.equals(listopertype, "1")) {
                    return "0";
                }
                break;
            case "M":
                if (StringUtils.equals(listopertype, "1") || StringUtils.equals(listopertype, "2")) {
                    return "0";
                }
                break;
            case "D":
                if (StringUtils.equals(listopertype, "1")) {
                    return "G";
                }
                if (StringUtils.equals(listopertype, "3")) {
                    return "0";
                }
                break;
        }
        return null;
    }

}
