package com.brilliance.isc.common.cbsmod;

import com.brilliance.isc.bo.Cbb;
import com.brilliance.isc.common.cbsmod.service.CbsmodService;
import com.brilliance.isc.common.stgmod.service.StgmodService;
import com.brilliance.isc.common.stgmod.vo.StgmodVo;
import com.brilliance.isc.common.util.SettleExceptionUtils;
import com.brilliance.isc.common.util.Utils;
import com.brilliance.isc.mda.dao.CbbMapper;
import com.brilliance.isc.utils.StringUtils;
import com.brilliance.mda.runtime.mda.IStream;
import com.brilliance.mda.runtime.mda.impl.StreamImpl;
import com.brilliance.mda.runtime.mda.util.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

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


@Component
public class Cbsget {

    @Autowired
    private CbsmodService cbsmodService;

    @Autowired
    private CbbMapper cbbMapper;

    @Autowired
    private StgmodService stgmodService;

    public static Date sdbRngGetMinDat() {
        return Strings.parseDate("01/01/1900");
    }

    public static Date sdbRngGetMaxDat() {
        return Strings.parseDate("31/12/2299");

    }

    public void getAamCbsPerDate(Map<String, Cbb> cbbMap, String objType, String inr, String modPath, Date argDat) {
        //! Reads additional amounts into passed ArgGrp
        //! Loads CBB MAXAAM and OPNAAM inside ArgGrp
        //! To be called in GetxxDCbsPerDate in xxDLODs of contracts which supports additional amounts if contract is available
        // get the CBB modules
        String maxPath = "MAX2";
        String opnPath = "OPN2";
        Cbb maxMod = cbbMap.get(maxPath);
        if( maxMod == null )
        {
            SettleExceptionUtils.sysDump(maxPath + " is not a CBB-Module - please check definition in contract group.");
        }
        Cbb opnMod = cbbMap.get(opnPath);
        if( opnMod == null )
        {
            SettleExceptionUtils.sysDump(opnPath + " is not a CBB-Module - please check definition in contract group.");
        }
        // Load CBBs if no empty contract
        if( MdaUtils.isEmpty(inr) )
        {
            SettleExceptionUtils.sysDump("GetAAMCbsPerDate called for contract with empty INR. The passed contract group is " + modPath);
        }
        else
        {
            cbsmodService.cbsGetBalance(maxMod,objType,inr,"MAXSUM",getAamExtId(),argDat);
            cbsmodService.cbsGetBalance(opnMod,objType,inr,"OPN",getAamExtId(),argDat);
        }
        //DO5DOS.011086 MAX3 not in all business sectors available
        // get the CBB modules
        maxPath =  "MAX3";
        opnPath =  "OPN3";
        Cbb maxModtst = cbbMap.get(maxPath);
        if( maxModtst != null )
        {
            maxMod = maxModtst;

                opnMod = cbbMap.get(opnPath);
                if( opnMod == null )
                {
                    SettleExceptionUtils.sysDump(opnPath + " is not a CBB-Module - please check definition in contract group.");
                }
                // Load CBBs if no empty contract
                if( MdaUtils.isEmpty(inr) )
                {
                    SettleExceptionUtils.sysDump("GetAAMCbsPerDate called for contract with empty INR. The passed contract group is " + modPath);
                }
                else
                {
                    cbsmodService.cbsGetBalance(maxMod,objType,inr,"MAXSUM",getAamExtId(),argDat);
                    cbsmodService.cbsGetBalance(opnMod,objType,inr,"OPN",getAamExtId(),argDat);
                }
        }
        // DNGDEV.001449 used for counter guarantee
        String macPath = "MAC2";
        String opcPath = "OPC2";
        Cbb macModtst = cbbMap.get(macPath);
        if( macModtst != null ) {
            Cbb macMod = macModtst;
            Cbb opcMod = cbbMap.get(opcPath);
            if( opcMod == null ) {
                SettleExceptionUtils.sysDump(opnPath + " is not a CBB-Module - please check definition in contract group.");
            }
            if( MdaUtils.isEmpty(inr) ) {
                SettleExceptionUtils.sysDump("GetAAMCbsPerDate called for contract with empty INR. The passed contract group is " + modPath);
            } else {
                cbsmodService.cbsGetBalance(macMod,objType,inr,"MACSUM",getAamExtId(),argDat);
                cbsmodService.cbsGetBalance(opcMod,objType,inr,"OPC",getAamExtId(),argDat);
            }
        }

    }

    public  String getAamExtId()
    {
        //! returns EXTID under which additional amounts are stored
        return  "AMT2";

    }
 /**
     * source:cbsget.0006.script
     */
    public void gridCfgAddCbs(StgmodVo stgmod, String argIns, String argCbc, String argExtid, String argBusIns, String argTyp) {
        //! Routine to add a reference to a cbs column within an streamgrid definition.
        //! This routine is a supporting routine to the set of GridCfg routines within STGMOD.
        //! ArgIns new instance (default = (first) passed Cbc)
        //! ArgCbc column or comma separated list of CBC`s
        //! ArgExtId Extid passed to CbsGetCbbSql which is used to generate the sql condition
        //! ArgBusIns Instance of the referred to contract
        //! ArgTyp holds `link` or `join` depending on the requested connection
        //!
        //! Corresponding routines: GridCfgAddCol, GridCfgAddFld, GridCfgAddJoinIns, GridCfgAddLinkIns, GridCfgAddPara, GridCfgAddPts, GridCfgInit, GridCfgLoadTds, GridCfgSetDefaultOrder, GridCfgSetPromptStream, GridCfgStore
        String tbl = stgmodService.gridCfgGetTbl4Ins(stgmod, argBusIns);
        String ins = argIns;
        int pos = 0;
        if (MdaUtils.isEmpty(ins)) {
            pos = Strings.pos(argCbc, ",");
            if (pos == 0) {
                ins = argCbc;
            } else {
                ins = Strings.mid(argCbc, 1, pos - 1);
            }
        }
        String chk = Strings.toLower(argTyp);
        if (MdaUtils.compareTo(chk, "link") != 0 && MdaUtils.compareTo(chk, "join") != 0) {
            // Platform.sysDump(Strings.formatText("STGMOD.GridCfgAddPts: in definition of instance $1 type $2 is used.\nOnly link or join are allowed.",argIns,argTyp));
        }
        String sql = cbsGetCbbSql(sqlLit(tbl), ">>" + argBusIns + ".INR<<", ins, argCbc, argExtid, getRelevantDateForBalances());
        if (MdaUtils.compareTo(chk, "link") == 0) {
            sql = sql + " order by " + ins + ".CBC";
        }
        String cmd = Strings.formatText("GridCfgAdd$1Ins( \"$2\", \"CBB\", \"$3\" )", argTyp, ins, sql);
//        Modules.invokeExpress((IModule) stgmod, cmd, -1);

    }

    /**
     * source:cbsget.0003.script
     */
    public List<String> cbsGetUnbalancedExtIds(String objTyp, String objInr, String cbcArg) {
        //! The pupose of this function is to retrieve a textblock with all
        //! IDs used by a certain object within a certain column which are not balanced
        //!
        // use passed module to set the object-type and INR
        //! If entries with a blank ID are stored, the blank ID is always
        //! the first line in the textblock
        List<Cbb> cbbList = cbbMapper.getCbbListByObjTypeAndInrAndCbcByOrder(objTyp, objInr, cbcArg);
        List<String> extidList = new ArrayList<>();
        if (cbbList != null && cbbList.size() > 0) {
            cbbList.forEach(cbb -> {
                if (StringUtils.isNotEmpty(cbb.getExtid())) {
                    if (!extidList.contains(cbb.getExtid())) {
                        extidList.add(cbb.getExtid());
                    }
                }
            });
        }
        return extidList;
    }
    public String cbsGetCbbSql(String argObj, String argObjInr, String argCbbIns, String argCbc, String argExtid, Date argDat) {
        if (MdaUtils.isEmpty(argObjInr)) {
            SettleExceptionUtils.sysDump("CbsGetCbbSql: The inr of the object is passed as an empty string but has to be specified.\nPlease correct the calling routine and supply an inr for the object.");
        }
        String cbbIns = NULLSTR;
        if (MdaUtils.isEmpty(argCbbIns)) {
            cbbIns = "";
        } else {
            cbbIns = argCbbIns + ".";
        }
        String sel = "( " + cbbIns + "OBJTYP = " + argObj + " AND " + cbbIns + "OBJINR = " + argObjInr;
        sel = sel + " AND " + createDatRngSqlPerDat(cbbIns, argDat);
        if (!MdaUtils.isEmpty(argExtid)) {
            sel = sel + " AND " + cbbIns + "EXTID " + internalGenSqlSet(argExtid);
        }
        if (!MdaUtils.isEmpty(argCbc)) {
            sel = sel + " AND " + cbbIns + "CBC " + internalGenSqlSet(argCbc);
        }
        sel = sel + " )";
        return sel;

    }

    /**
     * source:rngmod.0011.script
     */
    public String createDatRngSqlPerDat(String argIns, Date argDat) {
        if (MdaUtils.isEmpty(argDat)) {
            SettleExceptionUtils.sysDump("RNGMOD.CreateDatRngSqlPerDat: the passed Perdat is the Nulldate. A real date has to be passed.");
        } else {
            if (Dates.diff(argDat, sdbRngGetMinDat()) < 0 || Dates.diff(argDat, sdbRngGetMaxDat()) > 0) {
                SettleExceptionUtils.sysDump("RNGMOD.CreateDatRngSqlPerDat: The passed Perdat " + Formats.format(argDat, "YYYYMMDD") + " is outside the valid range.");
            }
        }
        return createDatRngSqlIns(argIns, Utils.dbSqlDate(argDat));

    }

    public String createDatRngSqlIns(String argIns, String argFld) {
        String ins = NULLSTR;
        if (MdaUtils.isEmpty(argIns)) {
            ins = "";
        } else {
            if (MdaUtils.compareTo(Strings.mid(argIns, Strings.len(argIns), 1), ".") == 0) {
                ins = argIns;
            } else {
                ins = argIns + ".";
            }
        }
        // The result will be
        // "( <Ins>.BEGDAT <= <fieldref> AND <Ins>.ENDDAT > <fieldref> )"
        return "( " + ins + "BEGDAT <= " + argFld + " AND " + ins + "ENDDAT > " + argFld + " )";

    }

    public String internalGenSqlSet(String argListe) {

        int begPos = 1;
        IStream argstm = new StreamImpl();
        Streams.streamClear(argstm);
        String rtn = NULLSTR;
        // ####### ��д LABEL��GOTO   ####    label NxtElm
        while (true) {
            // Search for next delimiter
            int len = Strings.pos(Strings.mid(argListe, begPos), ",");

            if (len == 0) {
                // if no delimiter found, check whether first arg to avoid
                // "IN set" construct and take "= literal"
                if (begPos == 1) {
                    rtn = " = " + sqlLit(argListe);
                    break; // ####### ��д LABEL��GOTO  ####   goto Done
                }
                // if no delimiter found, take rest
                len = Strings.len(Strings.mid(argListe, begPos)) + 1;
            }
            // If a value has to be processed
            String elm = NULLSTR;
            if (len > 1) {
                // eliminate leading and trailing spaces
                elm = Strings.trim(Strings.mid(argListe, begPos, len - 1));
                // search for double entries and include only new entries
                if (Streams.streamSearch(argstm, elm) == 0) {
                    Streams.streamInsert(argstm, -1, elm);
                }
                begPos = begPos + len;
                if (begPos <= Strings.len(argListe)) {
                    continue; // ####### ��д LABEL��GOTO  ####   goto NxtElm
                }
            }
            // transform list of values into the set format
            String list = "";
            String con = "";
            int stmCnt = Streams.streamCount(argstm);
            for (int idx = 1; idx <= stmCnt; idx++) {
                list = list + con + " " + sqlLit(Strings.getLine(argstm, idx));
                con = ",";
            }
            rtn = " IN (" + list + ")";
            break;
        }
        return rtn;

    }

    public Date getRelevantDateForBalances() {

        return Strings.parseDate("30/12/2299");

    }

    public String sqlLit(String argTxt) {
        String arg = NULLSTR;
        if (MdaUtils.isEmpty(argTxt)) {
            arg = " ";
        } else {
            arg = Strings.trim(argTxt);
        }
        // search for single quotes as they have to be doubled
        int pos = Strings.pos(arg, "'");
        int nxt = pos;
        while (nxt > 0) {
            arg = Strings.mid(arg, 1, pos - 1) + "''" + Strings.mid(arg, pos + 1);
            nxt = Strings.pos(Strings.mid(arg, pos + 2), "'");
            pos = pos + nxt + 1;
        }
        return "'" + arg + "'";

    }
}
