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

import com.brilliance.mda.runtime.mda.util.Dates;
import com.brilliance.mda.runtime.mda.util.Decimals;
import com.brilliance.mda.runtime.mda.util.MdaUtils;
import com.brilliance.mda.runtime.mda.util.Strings;
import com.brilliance.isc.bo.*;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.counter.service.CounterService;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.ordmod.service.OrdmodService;
import com.brilliance.isc.common.ordmod.vo.OrdmodVo;
import com.brilliance.isc.common.sysmod.SysmodService;
import com.brilliance.isc.common.transaction.help.TransactionHelpService;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.mda.dao.OrdMapper;
import com.brilliance.isc.mda.dao.OreMapper;
import com.brilliance.isc.utils.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;

import static com.brilliance.mda.runtime.mda.Constants.NULLSTR;
import static com.brilliance.mda.runtime.mda.Constants.tdContextTZSYSTEM;

@Service
public class OrdmodServiceImpl implements OrdmodService {

    private Logger log = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private OreMapper oreMapper;
    @Autowired
    private OrdMapper ordMapper;

    @Autowired
    private CounterService counterService;

    @Autowired
    private OrdmodService ordmodService;

    @Autowired
    private SysmodService sysmodService;

    @Autowired
    private TransactionHelpService transactionHelpService;


    /**
     *   source:ordmod.0009.script
     *   @Init(order=1000)
     */
    public String getActflg() {
        return "X";
    }

    /**
     *   source:ordmod.0000.script
     */
    public void ordUpdate(OrdmodVo ordmod, String newStatus) {
        //! Create or Update ORD
        //! updates the content of ORD
        //! updates respective creates ORD record and creates ORE record
        //! ORD must be initialized before with either ORDNew or ORDReadHold or ORDReadLock
        if( MdaUtils.isEmpty(this.getActflg())) {
           return;
        }
        String transName = SettleContext.getTransName();
        if(StringUtils.isEmpty(transName)){
            transName=ordmod.getOrd().getFrm();
        }
        Ore ore = ordmod.getOre();
        Ord ord = ordmod.getOrd();
        List<Ore> oreList = ordmod.getOreList();

        ore.setEnddattim( Dates.now());
        // ore.setSsninr(SettleContext.getUserSession().getSsn().getInr());
        calcDur(ord.getStadattim(), ordmod);
        ord.setStadattim(ore.getEnddattim());
        if( MdaUtils.compareTo(transName,"TRNCOR") == 0 ) {
            ord.setInftxt(Utils.getFieldValue(transactionHelpService.getTransactionStoreSet().getRec(),"inftxt").toString());
        }
        if(!MdaUtils.isEmpty(newStatus) ) {
            ord.setSta( newStatus);
        }
/*        if( MdaUtils.compareTo(newStatus,"CTR") == 0
            || MdaUtils.compareTo(newStatus,"CMR") == 0
            || MdaUtils.compareTo(newStatus,"DES") == 0 ) {
            ord.setSdhflg( "");
        }*/
        //ORD表中添加FMT标志，确保同一笔交易核心只处理一次
        //八位日期+八位流水
        /**
         if GetFramename == "CPTATO" or GetFramename == "DFTSET" or GetFramename == "DFTMSG" then
         **/
        String date = NULLSTR;
        String cou = NULLSTR;
        if( MdaUtils.compareTo(transName,"CPTATO") == 0
                || MdaUtils.compareTo(transName,"DFTSET") == 0
                || MdaUtils.compareTo(transName,"DFTMSG") == 0
                || MdaUtils.compareTo(transName,"CPTECO") == 0 ) {
            //当标志位为空时添加标志位数据
            if( MdaUtils.isEmpty(ord.getFmtflg()) ) {
                date = MdaUtils.toString(Dates.getYear(Dates.today()),4) +
                        MdaUtils.toString(Dates.getMonth(Dates.today()),-2) +
                        MdaUtils.toString(Dates.getDay(Dates.today()),-2);
                cou = counterService.dbCounterFormat("FMT");
                ord.setFmtflg( date + cou);
            }
        }
        //设置收单行标志
//        if( ! MdaUtils.isEmpty(ordmod.getSdhflg()) || sysmodService.isSdhBusiness() ) {
//            ordmod.getOrd().setSdhflg( "X");
//        }
        if( MdaUtils.compareTo(ordmod.getOrdinr(),"NEW") == 0 ) {
            if( MdaUtils.isEmpty(ord.getInr()) ) {
                ord.setInr(counterService.dbCounterFormat("ORD"));
            }
            ordmod.setOrdinr(ord.getInr());
            // create record ORD
            Utils.sdbEtySetRec(ord,"ORD",SettleContext.getUserEtg().getExtkey(), SettleContext.getUserEty().getExtkey());
            ordMapper.insert(ordmod.getOrd());
        } else {
            if( MdaUtils.compareTo(ordmod.getOrdinr(),ord.getInr()) != 0 || MdaUtils.isEmpty(ord.getInr()) ) {
                throw new CommonServiceException("ORD not registered");
            } else {
                ordMapper.updateByPrimaryKey(ordmod.getOrd());
            }
        }
        if(oreList!=null) {
            calcDurList(ord.getStadattim(), ordmod);
            oreList.forEach(item -> {
                if(StringUtils.isEmpty(item.getOrdinr())){
                    item.setOrdinr(ordmod.getOrdinr());
                    item.setFrm(SettleContext.getTransName());
                    item.setEnddattim(Dates.now());
                    item.setUsr(SettleContext.getUserSession().getUsr().getExtkey());
                    item.setBchkeyinr(SettleContext.getUserSession().getOrgBch().getInr());
                    oreMapper.insert(item);
                }
            });
        }
//         if(!Objects.equals(newStatus,"BRK") ||(Objects.equals(newStatus,"BRK") && oreList==null)){
            // fill rest of ORE and create record
            ore.setOrdinr(ordmod.getOrdinr());
            ordmod.setOrdinr("");
            ore.setTyp(transNewTyp(newStatus));
            ore.setFrm(transName);
            ore.setUsr(SettleContext.getUserSession().getUsr().getExtkey());
            // ore.setSsninr(SettleContext.getUserSession().getSsn().getInr());
            ore.setRoutxt(ordmod.getRoutxt());//复核记录
            if( MdaUtils.compareTo(transName,"SPTROU") == 0
                    || MdaUtils.compareTo(transName,"SPTINC") == 0 ) {
                ore.setTyp("ROU");
            }
            ore.setBchkeyinr(SettleContext.getUserSession().getOrgBch().getInr());
            oreMapper.insert(ordmod.getOre());
//        }
    }

    public void ordUpdate(OrdmodVo ordmod, Trn argTrn, String newStatus) {
        //驳回更新ord，ore数据
        if( MdaUtils.isEmpty(this.getActflg())) {
            return;
        }
        String transName = SettleContext.getTransName();
        if(StringUtils.isEmpty(transName)){
            transName=ordmod.getOrd().getFrm();
        }
        Ore ore = ordmod.getOre();
        Ord ord = ordmod.getOrd();
        List<Ore> oreList = ordmod.getOreList();

        ore.setEnddattim( Dates.now());
        calcDur(ord.getStadattim(), ordmod);
        ord.setStadattim(ore.getEnddattim());
        if( MdaUtils.compareTo(transName,"TRNCOR") == 0 ) {
            ord.setInftxt(Utils.getFieldValue(transactionHelpService.getTransactionStoreSet().getRec(),"inftxt").toString());
        }
        if(!MdaUtils.isEmpty(newStatus) ) {
            ord.setSta( newStatus);
        }
        String date = NULLSTR;
        String cou = NULLSTR;
        if( MdaUtils.compareTo(transName,"CPTATO") == 0
                || MdaUtils.compareTo(transName,"DFTSET") == 0
                || MdaUtils.compareTo(transName,"DFTMSG") == 0
                || MdaUtils.compareTo(transName,"CPTECO") == 0 ) {
            //当标志位为空时添加标志位数据
            if( MdaUtils.isEmpty(ord.getFmtflg()) ) {
                date = MdaUtils.toString(Dates.getYear(Dates.today()),4) +
                        MdaUtils.toString(Dates.getMonth(Dates.today()),-2) +
                        MdaUtils.toString(Dates.getDay(Dates.today()),-2);
                cou = counterService.dbCounterFormat("FMT");
                ord.setFmtflg( date + cou);
            }
        }
        if( MdaUtils.compareTo(ordmod.getOrdinr(),"NEW") == 0 ) {
            if( MdaUtils.isEmpty(ord.getInr()) ) {
                ord.setInr(counterService.dbCounterFormat("ORD"));
            }
            ordmod.setOrdinr(ord.getInr());
            // create record ORD
            Utils.sdbEtySetRec(ord,"ORD",SettleContext.getUserEtg().getExtkey(), SettleContext.getUserEty().getExtkey());
            ordMapper.insert(ordmod.getOrd());
        } else {
            if( MdaUtils.compareTo(ordmod.getOrdinr(),ord.getInr()) != 0 || MdaUtils.isEmpty(ord.getInr()) ) {
                throw new CommonServiceException("ORD not registered");
            } else {
                ordMapper.updateByPrimaryKey(ordmod.getOrd());
            }
        }
        if(oreList!=null) {
            calcDurList(ord.getStadattim(), ordmod);
            oreList.forEach(item -> {
                if(StringUtils.isEmpty(item.getOrdinr())){
                    item.setOrdinr(ordmod.getOrdinr());
                    item.setFrm(SettleContext.getTransName());
                    item.setEnddattim(Dates.now());
                    item.setUsr(SettleContext.getUserSession().getUsr().getExtkey());
                    item.setBchkeyinr(SettleContext.getUserSession().getOrgBch().getInr());
                    oreMapper.insert(item);
                }
            });
        }
        ore.setOrdinr(ordmod.getOrdinr());
        ordmod.setOrdinr("");
        ore.setTyp(transNewTyp(newStatus));
        ore.setFrm(argTrn.getInifrm());
        ore.setUsr(SettleContext.getUserSession().getUsr().getExtkey());
        ore.setRoutxt(ordmod.getRoutxt());//复核记录
        if( MdaUtils.compareTo(transName,"SPTROU") == 0
                || MdaUtils.compareTo(transName,"SPTINC") == 0 ) {
            ore.setTyp("ROU");
        }

        String bchkeyinr =oreMapper.getBchkeyinrByOre(argTrn.getOrdinr()).getBchkeyinr();
        ore.setBchkeyinr(bchkeyinr);
        oreMapper.insert(ordmod.getOre());
    }

    public void oreUpdate(OrdmodVo ordmod, String newStatus,String inifrm) {
        //驳回更新ord，ore数据
        Ore ore = ordmod.getOre();
        ore.setBegdattim(new Date());
        ore.setEnddattim( Dates.now());
        ore.setOrdinr(ordmod.getOrdinr());
        ore.setTyp(newStatus);
        ore.setFrm(inifrm);
        ore.setUsr(SettleContext.getUserSession().getUsr().getExtkey());
        ore.setRoutxt(ordmod.getRoutxt());//复核记录
        ore.setBchkeyinr(SettleContext.getUserSession().getOrgBch().getInr());
        oreMapper.insert(ordmod.getOre());
    }

    public String transNewTyp(String oldtyp){
        String newtyp="";
        if(sysmodService.isSdhBusiness()) {
            switch (oldtyp){
                case "BRK":
                    newtyp="SRK";
                    break;
                case "TRN":
                    newtyp="SRN";
                    break;
                case "COR":
                    newtyp="SOR";
                    break;
                default:
                    newtyp=oldtyp;
                    break;
            }
        }else{
            newtyp = oldtyp;
        }
        return newtyp;
    }

    /**
     *   source:ordmod.0001.script
     */
    public void ordReadLock(String argORDINR, OrdmodVo ordmod) {
        //! Register ORD for later update
        //! Must be called when handling is started
        //! Performs implicit commit due to SdbReadLock
        //! registers (and locks) ORD for later update via UpdateORD
        // if several ORDs are to be locked with ORDReadLock at one time,
        // each ORD must be reread with ORDReadHold before using ORDUpdate
        if( MdaUtils.isEmpty(this.getActflg()) ) {
           return;
        }
        if( MdaUtils.compareTo(argORDINR, ordmod.getOrdinr()) != 0 ) {
            if(!MdaUtils.isEmpty(ordmod.getOrdinr())) {
                ordmod.setOrdinr("");
            }
        }
        ordmod.setOre(new Ore());
        Ord ord = new Ord();
        ord.setInr(argORDINR);
        ord = ordMapper.selectByPrimaryKey(ord);
        ordmod.setOrd(ord);
        // store registered ORD
        ordmod.setOrdinr(ord.getInr());
        // initialize ORE
        ordmod.getOre().setBegdattim( Dates.now());

    }
    /**
     *   source:ordmod.0002.script
     */
    public void ordNew(OrdmodVo ordmod) {
        //! Register new ORD (to be created later by UpdateORD)
        if( MdaUtils.isEmpty(this.getActflg())) {
            return;
        }
        /*TODO if(!MdaUtils.isEmpty(this.getOrdinr()) ) {
            if(MdaUtils.compareTo(this.getOrdinr(),"NEW") != 0 ) {
                ctx.getDaoSession().dbFree(this.getOrd());
            }
        }*/
        ordmod.setOre(new Ore());
        ordmod.setOrd(new Ord());
        ordmod.setOrdinr("NEW");
        ordmod.getOrd().setInidattim( Dates.now());
        // initialize ORE
        ordmod.getOre().setBegdattim(ordmod.getOrd().getInidattim());
        ordSetTarget(ordmod, null);
    }
    /**
     *   source:ordmod.0003.script
     */
    public void ordReadHold(String argORDINR, OrdmodVo ordmod) {
        //! Register ORD for later update
        //! Can be called at any time before Update
        //! Avoids implicit commit due to Lock but BEGDATTIM must be set manually before update
        //! registers (and hold) ORD for later update via UpdateORD
        if( MdaUtils.isEmpty(this.getActflg())) {
           return;
        }
        if( MdaUtils.compareTo(argORDINR, ordmod.getOrdinr()) == 0 ) {
            // already held or locked
            return;
        }
        ordmod.setOrdinr( "");
        ordmod.setOre(new Ore());
        Ord ord = new Ord();
        ord.setInr(argORDINR);
        ord = ordMapper.selectByPrimaryKey(ord);
        ordmod.setOrd(ord);
        // store registered ORD
        ordmod.setOrdinr(ordmod.getOrd().getInr());
        // initialize ORE
        ordmod.getOre().setBegdattim( Dates.now());

    }
    /**
     *   source:ordmod.0004.script
     */
    public int convertTimeToSeconds(long timeStamp) {
        //! converts timestamp in format hh.mmss to seconds
        String timstr = MdaUtils.toString(Decimals.div(timeStamp,100)) + "000000"; // fill with trailing `0`
        int hh = Strings.parseInt(Strings.mid(timstr,3,2));
        int mm = Strings.parseInt(Strings.mid(timstr,5,2));
        int ss = Strings.parseInt(Strings.mid(timstr,7,2));
        return  hh * 3600 + mm * 60 + ss;

    }
    /**
     *   计算订单 等待时间 等等
     */
    public void calcDur(Date olddattim, OrdmodVo ordmod) {
        //! adjust BEGDATTIM and calculate ORE\\DUR
        //! calculate ORE\\WAI as difference between OLD and BEG
        // assert BEG and calculate duration
        Ore ore = ordmod.getOre();
        if( MdaUtils.isEmpty(ore.getBegdattim()) || Dates.diff(ore.getBegdattim(),ore.getEnddattim())>0 ) {
            ore.setBegdattim( ore.getEnddattim());
        }
        Long datediff = Dates.dateTimeDiff(ore.getEnddattim(),ore.getBegdattim());
        ore.setPrcdur( new BigDecimal(convertTimeToSeconds(datediff.intValue())));
        if (ore.getPrcdur().compareTo(new BigDecimal("9999999999")) > 0) {
            ore.setPrcdur(new BigDecimal("9999999999"));
        }
        if( MdaUtils.isEmpty(olddattim) ) {
            ore.setWaidur( new BigDecimal("0"));
        } else {
            datediff = Dates.dateTimeDiff(ore.getBegdattim(),olddattim);
            ore.setWaidur(new BigDecimal(convertTimeToSeconds(datediff.intValue())));
            if (ore.getWaidur().compareTo(new BigDecimal("9999999999")) > 0) {
                ore.setWaidur( new BigDecimal("9999999999"));
            }
        }

    }

    /**
     *   计算订单 等待时间 等等
     */
    public void calcDurList(Date olddattim, OrdmodVo ordmod) {
        //! adjust BEGDATTIM and calculate ORE\\DUR
        //! calculate ORE\\WAI as difference between OLD and BEG
        // assert BEG and calculate duration
        for (Ore ore : ordmod.getOreList()) {
            ore.setEnddattim(Dates.now());
            if( MdaUtils.isEmpty(ore.getBegdattim()) || Dates.diff(ore.getBegdattim(),ore.getEnddattim())>0 ) {
                ore.setBegdattim( ore.getEnddattim());
            }
            Long datediff = Dates.dateTimeDiff(ore.getEnddattim(),ore.getBegdattim());
            ore.setPrcdur( new BigDecimal(convertTimeToSeconds(datediff.intValue())));
            if (ore.getPrcdur().compareTo(new BigDecimal("9999999999")) > 0) {
                ore.setPrcdur(new BigDecimal("9999999999"));
            }
            if( MdaUtils.isEmpty(olddattim) ) {
                ore.setWaidur( new BigDecimal("0"));
            } else {
                datediff = Dates.dateTimeDiff(ore.getBegdattim(),olddattim);
                ore.setWaidur(new BigDecimal(convertTimeToSeconds(datediff.intValue())));
                if (ore.getWaidur().compareTo(new BigDecimal("9999999999")) > 0) {
                    ore.setWaidur( new BigDecimal("9999999999"));
                }
            }
        }
    }
    /**
     *   source:ordmod.0006.script
     */
    public String ordGetINR(OrdmodVo ordmod) {
        //! Returns INR of ORD that will be updated or create with next call to ORDUpdate
        //! ORD must be initialized before with either ORDNew or ORDReadHold or ORDReadLock
        if(MdaUtils.isEmpty(this.getActflg())) {
            return "";
        }
        if(MdaUtils.compareTo(ordmod.getOrdinr(),"NEW") == 0) {
            // ORD will be created by ORDUpdate
            if( MdaUtils.isEmpty(ordmod.getOrd().getInr()) ) {
                ordmod.getOrd().setInr(counterService.dbCounterFormat("ORD"));
            }
            return ordmod.getOrd().getInr();
        } else {
            // ORD will be updated by ORDUpdate
            return ordmod.getOrdinr();
        }
    }
    /**
     *   source:ordmod.0007.script
     */
    public void ordFree(OrdmodVo ordmod) {
        //! Free ORD
        //! Can be called at any time to free ORD
        //! Caution: Might optionally imply a DBCommit
        /*TODO 待实现dbFree
           if(!MdaUtils.isEmpty(ordmod.getOrd().getInr()) ) {
            if(MdaUtils.compareTo(ordmod.getOrdinr(),"NEW") != 0 ) {
                ctx.getDaoSession().dbFree(this.getOrd());
            }
        }*/
        ordmod.setOrdinr("");
        ordmod.getOrd().setInr("");

    }
    /**
     *   source:ordmod.0008.script
     */
    public void ordSetTarget(OrdmodVo ordmod, Date newDateTime) {
        //! Set Target Completion Time for Order
        // default setting is `today`
        // target completion time may be modified by
        // - changing ORDSetTarget in customer installation or
        // - calling ORDSetTarget in customer installation with different target time after call to ORDNew
        if( MdaUtils.isEmpty(this.getActflg())) {
           return;
        }
        if(MdaUtils.compareTo(ordmod.getOrdinr(),"NEW") == 0) {
            if( newDateTime == null ) {
                ordmod.getOrd().setTardattim(Dates.now());
                Dates.dateTimeSetTime(ordmod.getOrd().getTardattim(),23.59, tdContextTZSYSTEM);
            } else {
                ordmod.getOrd().setTardattim( newDateTime);
            }
        } else {
            throw new CommonServiceException("Target time can only be set when order is created.");
        }
    }


    /**
     * 接口收渠道及电商报文存交易节点信息方法
     * @param spt
     * @param smh
     */
    public String insertOrdForjk(Spt spt, Smh smh){
        //不用 ordemodService 单独写一套 ORDNew
        try {
            OrdmodVo ordmod = new OrdmodVo();
            ordmodService.ordNew(ordmod);

            ordmod.getOrd().setObjinr(spt.getObjinr());
            if (!MdaUtils.isEmpty(spt.getObjtyp())) {
                ordmod.getOrd().setObjtyp(Strings.mid(spt.getObjtyp(),1,3));
            }
            ordmod.getOrd().setSmhinr(smh.getInr());
            ordmod.getOrd().setExtkey(smh.getExtkey());
            ordmod.getOrd().setNam(smh.getNam());
            ordmod.getOrd().setFrm(spt.getFrm());
            //ord 保存  ore赋值  ORDUpdate
            ordmodService.ordUpdate(ordmod,"INC");
            log.info("ORD,ORE 表保存结束, ord.inr:{}", ordmod.getOrd().getInr());
            return ordmod.getOrd().getInr();
        } catch (Exception e) {
            log.error("保存ORD、ORE表节点信息失败，sptinr={}，smhinr={}",spt.getInr(),smh.getInr(),e);
            return null;
        }
    }
}
