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

import com.brilliance.isc.bo.*;
import com.brilliance.isc.common.cache.adr.AdrCacheService;
import com.brilliance.isc.common.cache.pta.PtaCacheService;
import com.brilliance.isc.common.cache.pty.PtyCacheService;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.converter.DtoMapper;
import com.brilliance.isc.common.fecmod.service.FecmodService;
import com.brilliance.isc.common.util.StringUtils;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.common.vo.BizInfoVo;
import com.brilliance.isc.common.vo.FecVo;
import com.brilliance.isc.mda.dao.CtyMapper;
import com.brilliance.isc.mda.dao.FecMapper;
import com.brilliance.isc.mda.dao.RegMapper;
import com.brilliance.mda.runtime.mda.impl.Argument;
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 org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

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

@Service("fecmodService")
public class FecmodServiceImpl implements FecmodService {

    @Autowired
    private AdrCacheService adrCacheService;

    @Autowired
    private CtyMapper ctyMapper;

    @Autowired
    private FecMapper fecMapper;

    @Autowired
    private PtaCacheService ptaCacheService;

    @Autowired
    private PtyCacheService ptyCacheService;

    @Autowired
    private RegMapper regMapper;

    /**
     * source:fecmod.0000.script
     */
    public FecVo getPtyFec(BizInfoVo rec, Date fecRefDat, BigDecimal argAmt, String argPtyInr, String argFeePri, Fee argFee) {
        //! get fee condition composed from various levels stored in FEC of fee ArgFee
        //! ArgCur    : currency of relevant amount (SYSISO)
        //! ArgAmt    : Relevant Amount  to be used to find correct condition tiered by amounts (negative amounts are converted to positive amounts)
        //! ArgRol    : Role code of party paying
        //! ArgPtyinr : INR of party paying
        //! ArgFeePri : Fee priority to be read - empty for all (common prorities ! and 0 are not supported alone).
        //! ArgFee    : Fee for which the condition is to retrieved
        //! ArgFec    : In FEC the composed condition is returned
        //! ArgFecLst : Stream with information about the entries condition is composed of.
        //!             The stream is requiered to show OIT-information of condition in SetOitForFec
        // read PTY, REG, CTY from database as key for FEC
        if (StringUtils.isEmpty(argFee.getInr())) {
            return null;
        }
        Pty wrkPty = loadWrkPty(argPtyInr);
        if(wrkPty == null){
            wrkPty = new Pty();
        }
        Cty wrkCty = null;
        Reg wrkReg = null;
        //根据wrkpty获取wrkcty wrkreg
        if (wrkPty != null) {
            if (!StringUtils.isEmpty(wrkPty.getRskcty())) {
                wrkCty = ctyMapper.selectByCod(wrkPty.getRskcty());
            } else {
                Pta pta = ptaCacheService.selectByPtyInrAndUsg(wrkPty.getInr(), "MAA");
                if (pta != null) {
                    Adr newAdr = adrCacheService.getAdrByInr(pta.getObjinr());
                    if (newAdr != null) {
                        wrkCty = ctyMapper.selectByCod(newAdr.getLoccty());
                    }
                }
            }
        }
        if (wrkCty != null && !StringUtils.isEmpty(wrkCty.getReg())) {
            wrkReg = regMapper.selectByCod(wrkCty.getReg());
        }
        String fecsql = "WHERE FEEINR = '" + argFee.getInr() + "'";
        fecsql += " AND LOWAMT <= " + argAmt.abs().toPlainString() + "";
        fecsql += " AND HIGAMT > " + argAmt.abs().toPlainString() + "";
        Date fecDate = fecRefDat == null ? Dates.today() : fecRefDat;
        String rngSql = "( BEGDAT <= " + Utils.dbSqlDate(fecDate) + " AND ENDDAT > " + Utils.dbSqlDate(fecDate) + " )";
        fecsql += " AND " + rngSql;

        String pfx = " AND (";
        if( MdaUtils.isEmpty(argFeePri) )
        {
            fecsql = fecsql + pfx + " FEEPRI in ('!', '0')";
            pfx = " OR (";
        }
        Argument<String> fecsqlBox = new Argument<String>("",fecsql);
        Argument<String> pfxBox = new Argument<String>("",pfx);
        createFecSql(rec, wrkReg, wrkCty, wrkPty, fecsqlBox, pfxBox, argFeePri);

        fecsql = fecsqlBox.value;
        pfx = pfxBox.value;

        // no read, if no feepri is selected
        if( MdaUtils.compareTo(pfx," AND (") == 0 ) {
            return null;
        }
        if( MdaUtils.isEmpty(argFeePri) ) {
            fecsql = fecsql + " ) ";
        }
        fecsql = Utils.sdbEtyGenSql("FEC", fecsql);
        String sql = fecsql + " ORDER BY FEEPRI DESC";
        List<Fec> wrkfecList = fecMapper.selectFecByConditionSql(sql);
        if (wrkfecList != null && wrkfecList.size() > 0) {
            //获取到默认计费规则
            Fec defaultFec = null;
            Optional<Fec> defaultFecOptional = wrkfecList.stream().filter(fec -> "!".equals(fec.getFeepri())).findFirst();
            if (defaultFecOptional.isPresent()) {
                defaultFec = defaultFecOptional.get();
            }
            for (Fec wrkfec : wrkfecList) {
                //S 表示 使用新的计算条件  N表示使用默认的计算条件
                if (!"S".equalsIgnoreCase(wrkfec.getCalfcc())) {
                    continue;
                } else {
                    FecVo argFec = DtoMapper.INSTANCE.transfer(wrkfec);
                    /*FecVo argFec = new FecVo();
                    if(MdaUtils.compareTo(wrkfec.getCalfcc(),"S") == 0 ) {
                        argFec.setCalrul(wrkfec.getCalrul());
                        argFec.setSetbeg(wrkfec.getSetbeg());
                        argFec.setSetend(wrkfec.getSetend());
                    }
                    if(!MdaUtils.isEmpty(wrkfec.getCalcbs())) {
                        argFec.setCalcbs(wrkfec.getCalcbs());
                    }*/
                    if(MdaUtils.compareTo(wrkfec.getMaxfcc(),"S") == 0 ) {
                        argFec.setMaxamt(wrkfec.getMaxamt());
                        argFec.setMaxcur(wrkfec.getMaxcur());
                    }
                    if( MdaUtils.compareTo(wrkfec.getMinfcc(),"S") == 0 ) {
                        argFec.setMinamt(wrkfec.getMinamt());
                        argFec.setMincur(wrkfec.getMincur());
                    }
                    /*if( MdaUtils.compareTo(wrkfec.getRatfcc(),"S") == 0 ) {
                        argFec.setUntamt(wrkfec.getUntamt());
                        argFec.setRatcal(wrkfec.getRatcal());
                        argFec.setRatcur(wrkfec.getRatcur());
                    }*/
                    if( MdaUtils.compareTo(wrkfec.getMaxfcc(),"P") == 0 ) {
                        //%到旧的最大值
                        if (defaultFec != null) {
                            argFec.setMaxamt(Decimals.mul(argFec.getMaxamt(),( Decimals.add(1,( Decimals.div(defaultFec.getMaxamt(),100) )) )));
                        }
                    }
                    if( MdaUtils.compareTo(wrkfec.getMinfcc(),"P") == 0 ) {
                        //%到旧的最小值
                        if (defaultFec != null) {
                            argFec.setMinamt(Decimals.mul(argFec.getMinamt(), (Decimals.add(1, (Decimals.div(defaultFec.getMinamt(), 100))))));
                        }
                    }
                    /*if( MdaUtils.compareTo(wrkfec.getRatfcc(),"P") == 0 ) {
                        argFec.setUntamt(Decimals.mul(argFec.getUntamt(),( Decimals.add(1,( Decimals.div(wrkfec.getUntamt(),100) )) )));
                        argFec.setRatcal(Decimals.mul(argFec.getRatcal(),( Decimals.add(1,( Decimals.div(wrkfec.getRatcal(),100) )) )));
                    }*/
                    if( MdaUtils.compareTo(wrkfec.getMaxfcc(),"A") == 0 ) {
                        //+/-到旧的最大值
                        if (defaultFec != null) {
                            argFec.setMaxamt(Decimals.add(argFec.getMaxamt(), defaultFec.getMaxamt()));
                        }
                    }
                    if( MdaUtils.compareTo(wrkfec.getMinfcc(),"A") == 0 ) {
                        //+/-到旧的最小值
                        if (defaultFec != null) {
                            argFec.setMinamt(Decimals.add(argFec.getMinamt(), defaultFec.getMinamt()));
                        }
                    }
                    /*if( MdaUtils.compareTo(wrkfec.getRatfcc(),"A") == 0 ) {
                        argFec.setUntamt(Decimals.add(wrkfec.getUntamt(),argFec.getUntamt()));
                        argFec.setRatcal(Decimals.add(wrkfec.getRatcal(),argFec.getRatcal()));
                    }
                    if(!MdaUtils.isEmpty(wrkfec.getRatirs())) {
                        argFec.setRatirs(wrkfec.getRatirs());
                        argFec.setRatirsinc(wrkfec.getRatirsinc());
                    }
                    // set common fields
                    argFec.setSetchgflg(wrkfec.getSetchgflg());
                    argFec.setColltr(wrkfec.getColltr());
                    argFec.setClcdifflg(wrkfec.getClcdifflg());
                    // set remaining fields only if a new type of caclulation is set
                    if( MdaUtils.compareTo(wrkfec.getCalfcc(),"S") == 0 ) {
                        internalFecCpy(argFec, wrkfec);
                    }*/
                    return argFec;
                }
            }
        }
        return null;
    }

    /**
     * source:fecmod.0002.script
     */
    public void internalFecCpy(FecVo argTarFec, Fec argSrcFec) {
        //! Copy condition ArgSrcFec to ArgTarfec without fields with special handling in  getfec
        // The following fileds are not copied
        //   "CALRUL", "SETBEG", "SETEND", "CALCBS", "MAXAMT", "MAXCUR", "MINAMT", "MINCUR", "UNTAMT", "RATCAL", "RATIRS", "RATIRSINC"
        // remember fields not to copy
        String calrul = argTarFec.getCalrul();
        String setbeg = argTarFec.getSetbeg();
        String setend = argTarFec.getSetend();
        String calcbs = argTarFec.getCalcbs();
        BigDecimal maxamt = argTarFec.getMaxamt();
        String maxcur = argTarFec.getMaxcur();
        BigDecimal minamt = argTarFec.getMinamt();
        String mincur = argTarFec.getMincur();
        BigDecimal untamt = argTarFec.getUntamt();
        BigDecimal ratcal = argTarFec.getRatcal();
        String ratirs = argTarFec.getRatirs();
        String ratirsinc = argTarFec.getRatirsinc();
        String ratfcc = argTarFec.getRatfcc();
        // copy all fields
        DtoMapper.INSTANCE.fecToFecVo(argSrcFec, argTarFec);

        // reset fields not to copy
        argTarFec.setCalrul(calrul);
        argTarFec.setSetbeg(setbeg);
        argTarFec.setSetend(setend);
        argTarFec.setCalcbs(calcbs);
        argTarFec.setMaxamt(maxamt);
        argTarFec.setMaxcur(maxcur);
        argTarFec.setMinamt(minamt);
        argTarFec.setMincur(mincur);
        argTarFec.setUntamt(untamt);
        argTarFec.setRatcal(ratcal);
        argTarFec.setRatirs(ratirs);
        argTarFec.setRatirsinc(ratirsinc);
        if (MdaUtils.isEmpty(argTarFec.getRatfcc()) || MdaUtils.compareTo(argTarFec.getRatfcc(), "N") == 0) {
            argTarFec.setRatfcc(ratfcc);
        }
    }

    /**
     * source:fecmod.0004.script
     */
    public Pty loadWrkPty(String argptyinr) {
        Pty wrkPty = null;
        String res = argptyinr;
        while (true) {
            Pty pty = ptyCacheService.getPtyById(res);
            if (pty == null) {
                break;
            }
            wrkPty = pty;
            // check HBKCONFLG
            // 可能會有自指的現象，需要考慮
            if (!StringUtils.isEmpty(pty.getHbkconflg())
                && !StringUtils.isEmpty(pty.getHbkinr())
                && !pty.getHbkinr().equals(res)) {
                res = pty.getHbkinr();
                continue; //   ####   goto restart
            } else if (!StringUtils.isEmpty(pty.getHeqconflg())
                    && !StringUtils.isEmpty(pty.getHeqinr())
                    && !pty.getHeqinr().equals(res)) {
                // check HEQACCFLG
                // 可能會有自指的現象，需要考慮
                res = pty.getHeqinr();
                continue; //   ####   goto restart
            } else {
                break;
            }
        }
        return wrkPty;
    }

    /**
     * source:fecmod.0005.script
     */
/*TODO 后续优化
    @JsonIgnore
    @TDStatic
    public String setOitForFec(IStream argFecLst, String argObjNam, String argLev, String argTypPfx) {
        //! Routine to load all fitting Infotexts for a composed fee condition into SYSWRN and check for stop level
        //! which are equal or beyond a passed threshold.
        //!
        //! The routine returns all texts of entries which have an INFLEV which is
        //! the same or greater than the passed threshold. The returned text should
        //! be used to issue an error or erroronfield to show this errormessage directly
        //! associated to the originating field.
        //!
        //! ArgFecLst hold the information about the FEC rows loaded to compose teh condition as returned from GetPtyFec
        //! ArgTypPfx holds the SYSWRN Id prefix to be used for the found infotexts
        //! ArgObjNam a short textual description of the object used in the message heading to identify the object.
        //!           SetOitForFec adds additional information about the priority of condition
        //! ArgLev holds an optional stop threshold.
        // Initialze registers and open SYSWRN-group with ArgTypPfx
        String res = "";
        int cnt = Streams.streamCount(argFecLst);
        BigDecimal dummy = Dynamic.oitSysWrnGrpRemove(argTypPfx);
        // call OitSysWrnForObj for all entries in ArgFecLst and collect result in $res
        // Caution: Decoding of ArgFecLst has to match with setting in GetPtyFec
        String line = NULLSTR;
        int postab = 0;
        String inr = NULLSTR;
        String feepri = NULLSTR;
        String objnam = NULLSTR;
        String feepriTxt = NULLSTR;
        String thisRes = NULLSTR;
        for (int i = 1; i <= cnt; i++) {
            line = Strings.getLine(argFecLst, i);
            postab = Strings.pos(line, TAB);
            inr = Strings.mid(line, 1, postab - 1);
            line = Strings.mid(line, postab + 1);
            postab = Strings.pos(line, TAB);
            feepri = Strings.mid(line, 1, postab - 1);
            objnam = argObjNam;
            feepriTxt = Codetables.getCodetableLabelOfTd(feepri, "FEC:FEEPRI", Systems.getLang());
            if (!MdaUtils.isEmpty(feepriTxt)) {
                objnam = objnam + "( " + feepriTxt + " )";
            }
            thisRes = Dynamic.oitSysWrnForObj("FEC", inr, objnam, argLev, argTypPfx + MdaUtils.toString(i, -3));
            if (!MdaUtils.isEmpty(thisRes)) {
                if (MdaUtils.isEmpty(res)) {
                    res = thisRes;
                } else {
                    res = res + CR + thisRes;
                }
            }
        }
        // Close SYSWRN-Group and return result
        Dynamic.sysWarningGroupCompleted();
        return res;
    }
*/

    /**
     * source:fecmod.0006.script
     */
    public boolean isUNTAMTValid(FecVo argFec) {
        //! returns true, if UNTAMT is valid/has to be shown.
        //! If TRUE, UNTAMT has to be shown, RATCAL is invalid
        //! If false, RATCAL has to be shown, UNTAMT is invalid
        switch (argFec.getCalrul()) {
            // only for fix fee, UNTAMT is used
            case "0":
                return true;
            // else not
            // break;
            default:
                return false;
        }
    }

    /**
     * source:fecmod.0007.script
     */
    public FecVo getFec(BizInfoVo rec, Date fecRefDat, BigDecimal argAmt, String argPtyInr, Fee argFee) {
        //! get fee condition composed from various levels stored in FEC of fee ArgFee
        //! ArgCur    : currency of relevant amount (SYSISO)
        //! ArgAmt    : Relevant Amount  to be used to find correct condition tiered by amounts
        //! ArgRol    : Role code of party paying
        //! ArgPtyinr : INR of party paying
        //! ArgFee    : Fee for which the condition is to retrieved
        //! ArgFec    : In FEC the composed condition is returned
        //! ArgFecLst : Stream with information about the entries condition is composed of.
        //!             The stream is requiered to show OIT-information of condition in SetOitForFec
        // Start with empty condition (if condition is set outside, Getfec should not be called)
        // Demobank is composing condition from ArgPtyInr for all levels
        return getPtyFec(rec, fecRefDat, argAmt, argPtyInr, "", argFee);
    }

    /**
     * source:fecmod.0009.script
     */

    public void createFecSql(BizInfoVo rec, Reg wrkreg, Cty wrkcty, Pty wrkpty, Argument<String> argSql, Argument<String> argpfx, String argFeePri) {
        // Busines-Sector
        if (StringUtils.isEmpty(argFeePri) || "$".equals(argFeePri)) {
            if (rec != null && StringUtils.isNotEmpty(rec.getObjtyp())) {
                String bus = rec.getObjtyp().substring(0, 2);
                argSql.value = argSql.value + argpfx.value + " FEEPRI = '$' AND OBJINR = '" + bus + "' )";
                argpfx.value = " OR (";
            }
        }
        // Entity
        if (StringUtils.isEmpty(argFeePri) || "*".equals(argFeePri)) {
            if (StringUtils.isNotEmpty(SettleContext.getUserEty().getInr())) {
                argSql.value = argSql.value + argpfx.value + "  FEEPRI = '*' AND OBJINR = '" + SettleContext.getUserEty().getInr() + "' )";
                argpfx.value = " OR (";
            }
        }
        // select on RegINR only if RegINR is set
        if (StringUtils.isEmpty(argFeePri) || "1".equals(argFeePri)) {
            if (wrkreg != null && StringUtils.isNotEmpty(wrkreg.getInr())) {
                argSql.value = argSql.value + argpfx.value + "  FEEPRI = '1' AND OBJINR = '" + wrkreg.getInr() + "' )";
                argpfx.value = " OR (";
            }
        }
        // select on CtyINR only if CtyINR is set
        if (StringUtils.isEmpty(argFeePri) || "2".equals(argFeePri)) {
            if (wrkcty != null && StringUtils.isNotEmpty(wrkcty.getInr())) {
                argSql.value = argSql.value + argpfx.value + " FEEPRI = '2' AND OBJINR = '" + wrkcty.getInr() + "' )";
                argpfx.value = " OR (";
            }
        }
        // Headquarter
        if (StringUtils.isEmpty(argFeePri) || "3".equals(argFeePri)) {
            if (wrkpty != null && StringUtils.isNotEmpty(wrkpty.getHeqinr())) {
                argSql.value = argSql.value + argpfx.value + " FEEPRI = '3' AND OBJINR = '" + wrkpty.getHeqinr() + "' )";
                argpfx.value = " OR (";
            }
        }
        // select relevant party
        if (StringUtils.isEmpty(argFeePri) || "4".equals(argFeePri)) {
            if (wrkpty != null && StringUtils.isNotEmpty(wrkpty.getInr())) {
                argSql.value = argSql.value + argpfx.value + " FEEPRI = '4' AND OBJINR = '" + wrkpty.getInr() + "' )";
                argpfx.value = " OR (";
            }
        }
    }
}
