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

import cn.hutool.core.lang.Assert;
import com.brilliance.mda.runtime.mda.IStream;
import com.brilliance.mda.runtime.mda.impl.Argument;
import com.brilliance.mda.runtime.mda.impl.StreamImpl;
import com.brilliance.mda.runtime.mda.util.*;
import com.brilliance.isc.bo.Fcp;
import com.brilliance.isc.bo.Pty;
import com.brilliance.isc.common.cache.pty.PtyCacheService;
import com.brilliance.isc.common.cbsmod.service.XrtmodService;
import com.brilliance.isc.common.context.SettleContext;
import com.brilliance.isc.common.exception.CommonServiceException;
import com.brilliance.isc.common.setfeg.fee.FeeSet;
import com.brilliance.isc.common.setfeg.fee.Setpty;
import com.brilliance.isc.common.setfeg.service.SetfegService;
import com.brilliance.isc.common.setfog.service.SetfogService;
import com.brilliance.isc.common.setfog.service.SetfolService;
import com.brilliance.isc.common.setfog.vo.SetfogVo;
import com.brilliance.isc.common.setfog.vo.SetfolVo;
import com.brilliance.isc.common.setglg.service.SetglgService;
import com.brilliance.isc.common.setmod.service.SetmodService;
import com.brilliance.isc.common.setmod.vo.SetmodVo;
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.mda.dao.FcpMapper;
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.HashMap;
import java.util.List;
import java.util.Map;

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

@Service
public class SetfogServiceImpl implements SetfogService {

    private static Logger log = LoggerFactory.getLogger(SetfogServiceImpl.class);

    @Autowired
    private SetfolService setfolService;

    @Autowired
    private SetglgService setglgService;

    @Autowired
    private SetfegService setfegService;

    @Autowired
    private XrtmodService xrtmodService;

    @Autowired
    private SetmodService setmodService;

    @Autowired
    private FcpMapper fcpMapper;

    @Autowired
    private PtyCacheService ptyCacheService;

    public FeeSet getFeeSet(){
        return setfegService.getFeeSet();
    }

    /**
     *   source:setfog.0004.script
     */
    @Override
    public String calcMacbog(SetmodVo setmod){
        IStream stm = new StreamImpl();
        Streams.streamSet(stm, setmod.getRoldsc());
        String macbog = Systems.macGen(stm,0);
        setmod.getSetfog().setMacbog(macbog);
        return macbog;
    }

    /**
     *   source:setfog.0002.script
     */
    @Override
    public String calcMaceog(SetmodVo setmodVo){
        String maceog = "";
        IStream stm = new StreamImpl();
        SetfogVo setfog = setmodVo.getSetfog();
        List<SetfolVo> setfols = setfog.getSetfol();
        int count = 0;
        if (setfols != null) {
            count = setfols.size();
        }
        if (count > 0) {
            for (int i=0; i<count; i++) {
                Assert.notNull(setfols);
                setfolService.calcMac(setfols.get(i), setmodVo);
                Streams.streamInsert(stm, 0, setfols.get(i).getMac());
            }
        }
        maceog = Systems.macGen(stm,0);
        setfog.setMaceog(maceog);
        return maceog;
    }

    /**
     *   source:setfog.0000.script
     */
    @Override
    public void recalcSetfogEog(SetmodVo setmodVo) {
        SetfogVo setfog = setmodVo.getSetfog();
        setglgService.setglgClrAmount(setmodVo.getSetglg(), "*SETFOG" );
        List<SetfolVo> setfols = setfog.getSetfol();
        int gridcnt = 0;
        if (setfols != null && setfols.size() > 0) {
            gridcnt = setfols.size();
        }
        setfog.setNetamt(setmodVo.getDocamt());
        for (int i=0; i<gridcnt; i++) {
            Assert.notNull(setfols);
            SetfolVo setfol = setfols.get(i);
            if(!StringUtils.isEmpty(setfol.getPtypay()) && ! StringUtils.isEmpty(setfol.getPtydbt()) && setfol.getAmt().compareTo(BigDecimal.ZERO) != 0 ) {
                if( "X".equals(setfol.getDsp()) || "S".equals(setfol.getDsp())) {
                    setglgService.setglgAddAmount(setmodVo.getSetglg(), "*SETFOG", setfol.getPtypay(), setfol.getCur(), setfol.getAmt().negate(), "FOG", "", "", "", "");
                    setglgService.setglgAddAmount(setmodVo.getSetglg(), "*SETFOG", setfol.getPtydbt(), setfol.getCur(), setfol.getAmt(), "FOG", "", "", "", "");
                }
            }
            setfog.setNetamt(setfog.getNetamt().add(setfol.getAmt().multiply(new BigDecimal(setfog.getForsgn()))));
        }
        String maceog = calcMaceog(setmodVo);
        setfog.setMaceog(maceog);
        setfog.setMaceogold(maceog);
    }
    /**
     *   source:setfog.0001.script
     */
    @Override
    public void getCurForChgRolbyDsp(SetfogVo setfog, String rol, String dsp, Argument<String> cur, Argument<BigDecimal> amt) {
        //! Get Foreign Charges currency and total amount to be paid by role ROL
        //! dsp X = collected, V = advised now, P = pool, A = all
        cur.value = "";
        amt.value = new BigDecimal("0");
        boolean found = false;
        List<SetfolVo> setfols = setfog.getSetfol();
        int count = 0;
        if (setfols != null) {
            count = setfols.size();
        }
        for (int i=0; i<count; i++) {
            Assert.notNull(setfols);
            SetfolVo setfol = setfols.get(i);
            if (!StringUtils.isEmpty(rol) && rol.equals(setfol.getPtydbt())
                && ((!StringUtils.isEmpty(dsp) && dsp.equals(setfol.getDsp())) || "A".equals(dsp))) {
                if(found && !cur.value.equals(setfol.getCur())) {
                    throw new CommonServiceException(Strings.getText("Fees in different currencies found for role $1, can not sum them up", rol));
                }
                cur.value = setfol.getCur();
                amt.value = Decimals.add(amt.value, setfol.getAmt());
                found = true;
            }
        }
    }
    /**
     *   source:setfog.0003.script
     */
    @Override
    public void recalcSetfogBog(SetmodVo setmod) {
        SetfogVo setfog = setmod.getSetfog();
        Map<String, Object> dyncMap = new HashMap<>();
        String chkrol = Strings.getLine(setmod.getRoldsc(),1);
        Setpty setpty = getFeeSet().getSetpty(Strings.mid(chkrol,1,Strings.pos(chkrol,TAB) - 1));
        if (setpty != null) {
            List<String> sqlList = setFcpSql(setfog, setmod);
            IStream ptyinrs = new StreamImpl();
            setmodService.fillPtyInrStm(ptyinrs);
            List<Fcp> newFcpList = new ArrayList<>();
            List<String> notMacthList = new ArrayList<>();
            for (int i=0; i<sqlList.size(); i++) {
                String sql = "select inr from fcp " + Utils.sdbEtyGenSql("FCP", sqlList.get(i));
                dyncMap.put("sql", sql);
                List<Fcp> fcps = fcpMapper.dyncRead(dyncMap);
                Fcp fcp = null;
                if (fcps != null && fcps.size()>0) {
                    fcp = fcps.get(0);
                }
                fcp = fcpMapper.selectByPrimaryKey(fcp);
                if (fcp != null) {
                    if(Streams.streamSearch(ptyinrs, fcp.getDbtptyinr()) == 0) {
                        Pty pty = ptyCacheService.getPtyById(fcp.getDbtptyinr());
                        if (pty != null) {
                            String ptynam = pty.getNam();
                            String ptyextkey = pty.getExtkey();
                            log.warn(Strings.getText("Foreign fee stored in pool for party $1($2) not loaded\\nThis transaction does not settle to that party", ptyextkey,ptynam));
                        }
                    } else {
                        List<SetfolVo> setfols = setfog.getSetfol();
                        if (setfols != null && setfols.size() > 0) {
                            for (int m=0; m<setfols.size(); m++){
                                SetfolVo setfolVo = setfols.get(m);
                                if (fcp.getInr().equals(setfolVo.getSrcfcpinr())) {
                                    buildSetfol(setfolVo, fcp);
                                } else {
                                    newFcpList.add(fcp);
                                    notMacthList.add(setfolVo.getSrcfcpinr());
                                }
                            }
                        }
                    }
                }
            }
            if (newFcpList.size() > 0) {
                newFcpList.forEach(fcp -> setfog.getSetfol().add(buildSetfol(new SetfolVo(), fcp)));
            }
            if (notMacthList.size() > 0) {
                notMacthList.forEach(srcfcpinr -> {
                    setfog.getSetfol().removeIf(setfolVo -> srcfcpinr.equals(setfolVo.getSrcfcpinr()));
                });
            }
        }
        String macbog = calcMacbog(setmod);
        setfog.setMacbog(macbog);
        setfog.setMacbogold(macbog);
    }
    /**
     * source:setfog.0005.script
     */
    public Fcp setwrkFcp(SetfolVo setfol, BizInfoVo rec, String trninr) {
        Fcp fcp = new Fcp();
        //! set FCP (foreign charges pool) fields
        fcp.setCur(setfol.getCur());
        fcp.setAmt(setfol.getAmt());
        fcp.setXrfcur(xrtmodService.sysiso());
        fcp.setXrfamt(xrtmodService.sysCurEqu(setfol.getCur(), setfol.getAmt(), Dates.today()));
        fcp.setDat1(setfol.getDat1());
        fcp.setDat2(setfol.getDat2());
        fcp.setPayptyinr(NULLSTR);
        Setpty setpty = getFeeSet().getSetpty(setfol.getPtypay());
        if (setpty != null) {
            fcp.setPayptyinr(setpty.getPtyInr());
        }
        fcp.setPayrol(setfol.getPtypay());
        fcp.setPaytxt(setfol.getTxtpay());
        setpty = getFeeSet().getSetpty(setfol.getPtydbt());
        if (setpty != null) {
            fcp.setDbtptyinr(setpty.getPtaInr());
        }
        fcp.setDbtrol(setfol.getPtydbt());
        fcp.setDbttxt(setfol.getTxtdbt());
        fcp.setModflg(setfol.getModflg());
        // Set OBJTYP/OBJINR of FEP to contract of role. If not avaiable use main contract (MTABUT\\REC)
        fcp.setObjtyp(rec.getObjtyp());
        fcp.setObjinr(rec.getObjinr());
        if ("X".equals(setfol.getDsp())) {
            fcp.setDontrninr(trninr);
            fcp.setDondat(Dates.today());
        }
        // if fee was advised before, store info from pool in new pool entry
        if ("V".equals(setfol.getDsp()) || "S".equals(setfol.getDsp())) {
            fcp.setDontrninr(trninr);
            fcp.setAdvdat(Dates.today());
        }
        if (("D".equals(setfol.getSrc()) || "A".equals(setfol.getSrc())) && ("D".equals(setfol.getDsp()) || "S".equals(setfol.getDsp()))) {
            fcp.setDontrninr(setfol.getAdvtrninr());
            fcp.setAdvdat(setfol.getAdvdat());
        }
        /*if ("S".equals(setfol.getDsp())) {
            fcp.setSepinr(setmod.getSep().getInr());
        }*/
        return fcp;
    }

    @Override
    public void registerSetfol(SetmodVo setmodVo, String ptydbt, String ptypay, String cur, BigDecimal amt) {
        boolean existFlag = false;
        List<SetfolVo> setfolList = setmodVo.getSetfog().getSetfol();
        SetfolVo srcSetfolVo = null;
        if (setfolList != null && setfolList.size() > 0) {
            for (SetfolVo setfolVo : setfolList) {
                if ("T".equals(setfolVo.getSrc())
                    && ptydbt.equals(setfolVo.getPtydbt())
                    && ptypay.equals(setfolVo.getPtypay())
                    && cur.equals(setfolVo.getCur())) {
                    existFlag = true;
                    srcSetfolVo = setfolVo;
                    break;
                }
            }
        }
        if (!existFlag) {
            if (amt.compareTo(BigDecimal.ZERO) != 0) {
                SetfolVo setfolVo = new SetfolVo();
                setfolVo.setSrc("T");
                setfolVo.setCur(cur);
                setfolVo.setAmt(amt);
                setfolVo.setPtydbt(ptydbt);
                setfolVo.setPtypay(ptypay);
                setfolList.add(setfolVo);
            }
        } else {
            if (amt.compareTo(BigDecimal.ZERO) == 0) {
                setfolList.remove(srcSetfolVo);
            } else {
                srcSetfolVo.setAmt(amt);
            }
        }
    }

    /**
     *   source:setfog.0006.script
     */
    @Override
    public void setDspPolDft(SetfogVo setfog, String argDspPolDft,String argDisableFlag) {
        //! to be used for settlement defaulting from RegisterSettlement functions
        //! sets the default disposition for pool entries
        //! Only necessary, if not "V" (i.e. pool entries are advised asap)
        setfog.setDsppoldft( argDspPolDft);
        setfog.setDsppoldftflg( argDisableFlag);

    }
    /**
     *   source:setfog.0008.script
     */
    public List<String> setFcpSql(SetfogVo setfog, SetmodVo setmod) {
        //! set SQL for fee pool according to FEPPNTLEV
        //! return a set of sql statements for each contract in ArgSqlStm
        String frame = SettleContext.getTransName();
        List<String> list = new ArrayList<>();
        // get pool entries of temporary settlement loaded (if loaded)
        // if no SEP is loaded ( SEP\\INR is empty) only entries without SEPINR set are loaded
        String prefixSql = "WHERE RPLTRNINR = ' ' AND DONTRNINR = ' ' ";
        /*if(!MdaUtils.isEmpty(setmod.getSep().getInr())) {
            prefixSql = prefixSql + " AND SEPINR in ( '" + setmod.getSep().getInr() + "', ' ' ) AND ";
        }
        else {
            prefixSql = prefixSql + " AND SEPINR = ' ' AND ";
        }*/
        prefixSql = prefixSql + " AND SEPINR = ' ' AND ";
        // get Records of central contract if FcPPNTLEV >= 0
        //电证买方信用证到单收取国外费用，修改重复收取费用，修改如下
        if(setfog.getFcppntlev() >= 0) {
            if(!"BDTDCK".equals(frame)) {
                if (!StringUtils.isEmpty(setmod.getRec().getObjinr())) {
                    list.add(prefixSql + " OBJTYP = '" + setmod.getRec().getObjtyp() + "' AND OBJINR = '" + setmod.getRec().getObjinr() + "'");
                }
            }
            if(setfog.getFcppntlev() >= 1) {
                // get records listed in \\setmod\\setaddconstm
                int addCnt = Streams.streamCount(setmod.getSetaddconstm());
                if( addCnt > 0 ) {
                    for(int i=1; i <= addCnt; i++) {
                        String line = Strings.getLine(setmod.getSetaddconstm(),i);
                        String objtyp = Strings.mid(line,1,Strings.pos(line,TAB) - 1);
                        String objinr = Strings.mid(line,Strings.pos(line,TAB) + 1);
                        list.add(prefixSql + " OBJTYP = '" + objtyp + "' AND OBJINR = '" + objinr + "'");
                    }
                }
            }
        }
        return list;
    }

    private SetfolVo buildSetfol(SetfolVo setfol, Fcp fcp) {
        if (setfol == null) {
            setfol = new SetfolVo();
        }
        // set technical fields from database to grid
        setfol.setSrcfcpinr(fcp.getInr());
        setfol.setAdvdat(fcp.getAdvdat());
        setfol.setAdvtrninr(fcp.getAdvtrninr());
        setfol.setSepinr(fcp.getSepinr());
        setfol.setModflg(fcp.getModflg());
        if (!setfol.isModified("amt")) {
            setfol.setAmt(fcp.getAmt());
        }
        if (!setfol.isModified("cur")) {
            setfol.setCur(fcp.getCur());
        }
        if (!setfol.isModified("ptydbt")) {
            Setpty setpty = setfegService.getFeeSet().getSetpty(fcp.getDbtptyinr());
            if (setpty != null) {
                setfol.setPtydbt(setpty.getRol());
            }
        }
        if (!setfol.isModified("ptypay")) {
            Setpty setpty = setfegService.getFeeSet().getSetpty(fcp.getPayptyinr());
            if (setpty != null) {
                setfol.setPtypay(setpty.getRol());
            }
        }
        if (!setfol.isModified("txtdbt")) {
            setfol.setTxtdbt(fcp.getDbttxt());
        }
        if (!setfol.isModified("txtpay")) {
            setfol.setTxtpay(fcp.getPaytxt());
        }
        if (!setfol.isModified("dat1")) {
            setfol.setDat1(fcp.getDat1());
        }
        if (!setfol.isModified("dat2")) {
            setfol.setDat2(fcp.getDat2());
        }
        return setfol;
    }


}
