package com.engine.salary.formlua.core;

import com.engine.salary.formlua.entity.parameter.DataType;
import com.engine.salary.formlua.entity.parameter.FuncNames;
import com.engine.salary.formlua.entity.standard.ExcelResult;
import com.engine.salary.formlua.func.compare.*;
import com.engine.salary.formlua.func.date.DateTimeService;
import com.engine.salary.formlua.func.date.DateTimeServiceImpl;
import com.engine.salary.formlua.func.finance.FinanceService;
import com.engine.salary.formlua.func.finance.FinanceServiceImpl;
import com.engine.salary.formlua.func.find.FindFuncsService;
import com.engine.salary.formlua.func.logic.IfOperator;
import com.engine.salary.formlua.func.logic.LogicService;
import com.engine.salary.formlua.func.logic.LogicServiceImpl;
import com.engine.salary.formlua.func.math.MathFuncsService;
import com.engine.salary.formlua.func.math.MathFuncsServiceImpl;
import com.engine.salary.formlua.func.string.StringFormulaService;
import com.engine.salary.formlua.func.string.StringFormulaServiceImpl;
import com.engine.salary.formlua.util.ExpressRegularUtil;
import com.ql.util.express.DynamicParamsUtil;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.IExpressContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.regex.PatternSyntaxException;

/**
 * 执行业务类
 */
public class QlExpress {

    public static ExpressRunner runner;

    static {
        runner = new ExpressRunner(true, false);
        runner.setShortCircuit(true);
    }

    private static boolean isInitialRunner = false;


//    AggregationFunc aggregationFunc;

    LogicService logicService = new LogicServiceImpl();

    DateTimeService dateTimeService = new DateTimeServiceImpl();

    StringFormulaService stringFormulaService = new StringFormulaServiceImpl();

    MathFuncsService mathFuncsService = new MathFuncsServiceImpl();

    FindFuncsService findFuncsService;

//    private ExcelFuncs excelFuncs;
//
//    private HrmDbService hrmDbService;

    private FinanceService financeService = new FinanceServiceImpl();
    //    private RemoteExcelformulaService remoteExcelformulaService;
    private String errorInfo;
    protected final Logger logger = LoggerFactory.getLogger(this.getClass());


    /**
     * @param statement 执行语句
     * @param context   上下文
     * @throws Exception
     */
    public ExcelResult execute(String statement, Map<String, Object> context) {
        String expressSql = statement;
        initRunner(runner);
        DynamicParamsUtil.supportDynamicParams = true;
        //初步的语法的格式校验
        IExpressContext<String, Object> expressContext = new QLExpressContext(context);
//		ThreadLocalData threadLocalData=new ThreadLocalData();
//		threadLocalData.setExpressContext(context);
//		ParamContext.get().setValue("formulaParam",threadLocalData);
//		ParamContext.get().setValue("currentUser",simpleEmployee);
        ExcelResult excelResult = new ExcelResult();
        try {
            ExpressRegularUtil.checkFuncExpress(expressSql);
            expressSql = expressSql.replaceAll("\\{", "");
            expressSql = expressSql.replaceAll("\\}", "");

            excelResult.setExpress(expressSql);
            excelResult.setExpressContext(expressContext);
            Object obj = runner.execute(expressSql, expressContext, null, true, false);

            if (obj != null) {
                if (obj instanceof DataType) {
                    DataType dataType = (DataType) obj;
                    excelResult.setData(dataType.getContent());
                    excelResult.setDataType(dataType.getDataType());
                } else {
                    excelResult.setData(obj);
                }
                excelResult.setStatus(true);
            } else {
                excelResult.setStatus(false);
            }
            return excelResult;
        } catch (Throwable e) {
            logger.error("express run err", e);
            while (e.getCause() != null) {
                e = e.getCause();
            }
            String errorMsg = e.getMessage();
            if (e instanceof PatternSyntaxException) {
                PatternSyntaxException patternSyntaxException = (PatternSyntaxException) e;
                errorMsg = patternSyntaxException.getDescription();
            } else {
                if (null != e.getCause()) {
                    errorMsg = e.getCause().getMessage();
                    if (e.getCause() instanceof InvocationTargetException) {
                        InvocationTargetException invocationTargetException = (InvocationTargetException) e.getCause();
                        errorMsg = invocationTargetException.getTargetException().getMessage();
                    }
                }
            }

            excelResult.setStatus(false);
            excelResult.setErrorMsg(errorMsg);
            return excelResult;
        }
    }

    private void initRunner(ExpressRunner runner) {
        if (isInitialRunner) {
            return;
        }
        synchronized (runner) {
            if (isInitialRunner) {
                return;
            }
            try {
                //比较函数
                runner.replaceOperator("=", new EqOperator("="));
                runner.replaceOperator("==", new EqOperator("="));
                runner.replaceOperator("!=", new NotEqueOperator("!="));

                runner.replaceOperator(">", new GreaterOperator(">"));
                runner.replaceOperator("<", new LessOperator("<"));
                runner.replaceOperator(">=", new GreaterEqOperator(">="));
                runner.replaceOperator("<=", new LessEqOperator("<="));

                runner.replaceOperator("+", new WOperatorAdd("+"));
                runner.replaceOperator("-", new WOperatorReduce("-"));
                runner.replaceOperator("*", new WOperatorMulti("*"));
                runner.replaceOperator("/", new WOperatorDiv("/"));
                //逻辑函数
                runner.replaceOperator("IF", new IfOperator("IF"));
                runner.addFunctionOfServiceMethod(FuncNames.AND.toString(), logicService, FuncNames.AND.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.OR.toString(), logicService, FuncNames.OR.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.NOT.toString(), logicService, FuncNames.NOT.getName(), new Class[]{Object[].class}, "");
                runner.replaceOperator("IN", new InOperator("in"));
                runner.addFunctionOfServiceMethod(FuncNames.LIKE.toString(), logicService, FuncNames.LIKE.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.ISEMPTY.toString(), logicService, FuncNames.ISEMPTY.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.TRUE.toString(), logicService, FuncNames.TRUE.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.FALSE.toString(), logicService, FuncNames.FALSE.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.IFS.toString(), logicService, FuncNames.IFS.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.SWITCH.toString(), logicService, FuncNames.SWITCH.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.FIND.toString(), logicService, FuncNames.FIND.getName(), new Class[]{Object[].class}, "");

                //日期函数
                runner.addFunctionOfServiceMethod("TODAY", dateTimeService, "today", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("NOW", dateTimeService, "now", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("DATEADD", dateTimeService, "dateAdd", new Class[]{Object[].class}, errorInfo);
                runner.addFunctionOfServiceMethod("DATEDIFF", dateTimeService, "dateDiff", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("DATEFORMAT", dateTimeService, "dateFormat", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("YEAR", dateTimeService, "year", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("MONTH", dateTimeService, "month", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("DAY", dateTimeService, "day", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("HOUR", dateTimeService, "hour", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("MINUTE", dateTimeService, "minute", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("SECOND", dateTimeService, "seconds", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("WEEKNUM", dateTimeService, "weekNum", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("WEEKDAY", dateTimeService, "weekDay", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("EOMONTH", dateTimeService, "eoMonth", new Class[]{Object[].class}, "");
//                runner.addFunctionOfServiceMethod("NETWORKDAYSPI", dateTimeService, "workdayIntl", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("CURRYEAR", dateTimeService, "currYear", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("CURRMONTH", dateTimeService, "currMonth", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("CURRDAY", dateTimeService, "currDay", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("CURRWEEK", dateTimeService, "currWeek", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("CURRHOUR", dateTimeService, "currHour", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("CURRMINUTE", dateTimeService, "currMinute", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("CURRSECOND", dateTimeService, "currSecond", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("MAXDATE", dateTimeService, "maxDate", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("MINDATE", dateTimeService, "minDate", new Class[]{Object[].class}, "");
//                runner.addFunctionOfServiceMethod("DAYOFMONTH", dateTimeService, "dayOfMonth", new Class[]{Object[].class}, "");

                //聚合函数
//                runner.addFunctionOfServiceMethod("COUNT", aggregationFunc, "counts", new Class[]{Object[].class}, "COUNT参数错误");
//                runner.addFunctionOfServiceMethod("AVG", aggregationFunc, "avgs", new Class[]{Object[].class}, "AVG参数错误");
//                runner.addFunctionOfServiceMethod("SUM", aggregationFunc, "sumNumber", new Class[]{Object[].class}, "SUM参数错误");
//                runner.addFunctionOfServiceMethod("MAX", aggregationFunc, "maxNumber", new Class[]{Object[].class}, "MAX参数错误");
//                runner.addFunctionOfServiceMethod("MIN", aggregationFunc, "minNumber", new Class[]{Object[].class}, "MIN参数错误");

                //字符串函数
                runner.addFunctionOfServiceMethod("CONCAT", stringFormulaService, "concatString", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("SEARCH", stringFormulaService, "search", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("TEXT", stringFormulaService, "text", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("PAD", stringFormulaService, "pad", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("REPLACE", stringFormulaService, "replace", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("VALUE", stringFormulaService, "value", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("LEN", stringFormulaService, "len", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("LEFT", stringFormulaService, "left", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("RIGHT", stringFormulaService, "right", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("MID", stringFormulaService, "mid", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("REPT", stringFormulaService, "repeat", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("TRIM", stringFormulaService, "trim", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("SCORE", stringFormulaService, "score", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("IDCARD", stringFormulaService, "idCard", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.ISSTRING.toString(), stringFormulaService, FuncNames.ISSTRING.getName(), new Class[]{Object[].class}, "");

                //数学函数
                runner.addFunctionOfServiceMethod("ROUNDUP", mathFuncsService, "roundUp", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("ROUND", mathFuncsService, "round", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod("ROUNDDOWN", mathFuncsService, "roundDown", new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.AGGREGATION.toString(), mathFuncsService, FuncNames.AGGREGATION.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.MOD.toString(), mathFuncsService, FuncNames.MOD.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.TRUNC.toString(), mathFuncsService, FuncNames.TRUNC.getName(), new Class[]{Object.class, Object.class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.ISINT.toString(), mathFuncsService, FuncNames.ISINT.getName(), new Class[]{Object[].class}, "");
                runner.addFunctionOfServiceMethod(FuncNames.ISNUMBER.toString(), mathFuncsService, FuncNames.ISNUMBER.getName(), new Class[]{Object[].class}, "");

                //查找函数
//                runner.addFunctionOfServiceMethod(FuncNames.CHOOSE.toString(), findFuncsService, "chooseOne", new Class[]{Object[].class}, "");
//                runner.addFunctionOfServiceMethod(FuncNames.MATCH.toString(), findFuncsService, "match", new Class[]{Object[].class}, "");
//                runner.addFunctionOfServiceMethod(FuncNames.VLOOKUPS.toString(), findFuncsService, "vlookups", new Class[]{Object[].class}, "");

                //数据库函数-hrm
//                runner.addFunctionOfServiceMethod(FuncNames.GETHRMNAME.toString(), hrmDbService, FuncNames.GETHRMNAME.getName(), new Class[]{Object[].class}, "");
//                runner.addFunctionOfServiceMethod(FuncNames.GETHRMMOBILE.toString(), hrmDbService, FuncNames.GETHRMMOBILE.getName(), new Class[]{Object[].class}, "");

                //财务函数
                runner.addFunctionOfServiceMethod(FuncNames.GETMONEY.toString(), financeService, FuncNames.GETMONEY.getName(), new Class[]{Object[].class}, "");

                //数据库函数-hrm
//				runner.addFunctionOfServiceMethod(FuncNames.GETHRMLOGINID.toString(), hrmDbService, "getHrmLoginId", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETHRMWORKCODE.toString(), hrmDbService, "getHrmWorkcode", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETHRMMANAGER.toString(), hrmDbService, "getHrmManager", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETHRMALLMANAGER.toString(), hrmDbService, "getHrmAllManager", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETHRMDEPARTMENT.toString(), hrmDbService, "getHrmDepartment", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETHRMSUBCOMPANY.toString(), hrmDbService, "getHrmSubcompany", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETDEPARTMENTNAME.toString(), hrmDbService, "getDepartmentName", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETDEPARTMENTCODE.toString(), hrmDbService, "getDepartmentCode", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETSUPERDEPARTMENT.toString(), hrmDbService, "getSuperDepartment", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETALLSUPERDEPARTMENT.toString(), hrmDbService, "getAllSuperDepartment", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETSUBCOMPANYNAME.toString(), hrmDbService, "getSubcompanyName", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETSUBCOMPANYCODE.toString(), hrmDbService, "getSubcompanyCode", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETSUPERSUBCOMPANY.toString(), hrmDbService, "getSuperSubcompany", new Class[]{Object[].class}, "");
//				runner.addFunctionOfServiceMethod(FuncNames.GETALLSUPERSUBCOMPANY.toString(), hrmDbService, "getAllSuperSubcompany", new Class[]{Object[].class}, "");

                //加载模块自定义函数
//				try {
//					List<ExcelFunc> otherFuncList=excelFuncs.getOtherFuncs();
//					if(otherFuncList!=null && otherFuncList.size()>0){
//						//为每个方法实例化一个ExcelExtendFuncService
//						for (ExcelFunc excelFunc:otherFuncList){
//							//每个接口调度类实例化时指定模块和函数名
//							ExcelExtendFuncService excelExtendFuncService=new ExcelExtendFuncServiceImpl(excelFunc.getModule(),excelFunc.getName());
//							//将自定义函数放入context上下文中
//							runner.addFunctionOfServiceMethod(excelFunc.getName(),excelExtendFuncService, RpcMethod.execute.toString(),new Class[]{Object[].class},"");
//						}
//					}
//				} catch (Exception e) {
//					logger.error("err",e);
//				}
            } catch (Exception e) {
                logger.error("初始化失败表达式", e);
                throw new RuntimeException("初始化失败表达式");
            }
        }
        isInitialRunner = true;
    }
}
