package com.engine.salary.formlua.func.math;

import com.alibaba.fastjson.JSONObject;
import com.engine.salary.formlua.entity.parameter.DataType;
import com.engine.salary.formlua.entity.parameter.FuncNames;
import com.engine.salary.formlua.util.ErrorUtil;
import com.engine.salary.formlua.util.ExcelParamUtil;
import com.engine.salary.formlua.util.IgnoreParamFilter;
import com.engine.salary.formlua.util.RegularUtil;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Random;

public class MathFuncsServiceImpl implements MathFuncsService {
    private final String randomNumber = "NUM";
    private final String randomChar = "CHAR";
    private final String randomNumANDChar = "FIX";

    @Override
    public DataType roundUp(Object... objects) {
        Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDUP.getName());
        Object number = null;
        Object object = objects[0];

        //小数位
        int numDigits = 0;
        Object numDigitsObj = null;

        //获取小数点位数参数
        if (objects != null && objects.length > 1) {
            numDigitsObj = objects[1];

            if (numDigitsObj != null && numDigitsObj instanceof DataType) {
                numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj, "");
            }
        }

        //整数校验
        if (numDigitsObj != null) {
            try {
                numDigits = (int) numDigitsObj;
            } catch (Exception e) {
                throw new RuntimeException("小数点位数必须是整数");
            }
        }

        if (object instanceof DataType) {
            DataType dataType = (DataType) object;
            if (dataType.getDataType().equalsIgnoreCase(DataType.STRING) || dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)) {
                JSONObject errorJson = ErrorUtil.buildError(FuncNames.ROUNDUP.toString(), errorNumber, errorNumber, "ROUNDUP函数只接受数字参数");
                throw new RuntimeException(errorJson.getString("msg"));
            }
            number = dataType.getContent();
        } else {
            BigDecimal db = new BigDecimal(object.toString());
            number = db;
        }
        if (!RegularUtil.isNumber(number)) {
            JSONObject errorJson = ErrorUtil.buildError(FuncNames.ROUNDUP.toString(), errorNumber, errorNumber, "ROUNDUP函数只接受数字参数");
            throw new RuntimeException(errorJson.getString("msg"));
        }

        BigDecimal bigDecimal = new BigDecimal(number + "");
        Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_CEILING).doubleValue();

        if (numDigits == 0) return new DataType(DataType.NUMBER, result.intValue());
        return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString());
    }

    @Override
    public DataType roundDown(Object... objects) {
        Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUNDDOWN.getName());
        Object number = null;
        Object object = objects[0];

        //小数位
        int numDigits = 0;
        Object numDigitsObj = null;

        //获取小数点位数参数
        if (objects != null && objects.length > 1) {
            numDigitsObj = objects[1];

            if (numDigitsObj != null && numDigitsObj instanceof DataType) {
                numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj, "");
            }
        }

        //整数校验
        if (numDigitsObj != null) {
            try {
                numDigits = (int) numDigitsObj;
            } catch (Exception e) {
                throw new RuntimeException("小数点位数必须是整数");
            }
        }

        if (object instanceof DataType) {
            DataType dataType = (DataType) object;
            if (dataType.getDataType().equalsIgnoreCase(DataType.STRING) || dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)) {
                return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString());
            }
            number = dataType.getContent();
        } else {
            BigDecimal db = new BigDecimal(object.toString());
            number = db;
        }

        if (!RegularUtil.isNumber(number)) {
            return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString());
        }

        BigDecimal bigDecimal = new BigDecimal(number + "");
        Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_FLOOR).doubleValue();

        if (numDigits == 0) return new DataType(DataType.NUMBER, result.intValue());
        return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString());
    }

    @Override
    public DataType round(Object... objects) {
        Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.ROUND.getName());
        Object number = null;
        Object object = objects[0];

        //小数位
        int numDigits = 0;
        Object numDigitsObj = null;

        //获取小数点位数参数
        if (objects != null && objects.length > 1) {
            numDigitsObj = objects[1];

            if (numDigitsObj != null && numDigitsObj instanceof DataType) {
                numDigitsObj = ExcelParamUtil.getParamContent(numDigitsObj, "");
            }
        }

        //整数校验
        if (numDigitsObj != null) {
            try {
                numDigits = (int) numDigitsObj;
            } catch (Exception e) {
                throw new RuntimeException("小数点位数必须是整数");
            }
        }

        if (object instanceof DataType) {
            DataType dataType = (DataType) object;
            if (dataType.getDataType().equalsIgnoreCase(DataType.STRING) || dataType.getDataType().equalsIgnoreCase(DataType.DATE) || dataType.getDataType().equalsIgnoreCase(DataType.OPTION)) {
                return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString());
            }
            number = dataType.getContent();
        } else {
            BigDecimal db = new BigDecimal(object.toString());
            number = db;
        }

        if (!RegularUtil.isNumber(number)) {
            return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString());
        }

        BigDecimal bigDecimal = new BigDecimal(number + "");
        Double result = bigDecimal.setScale(numDigits, BigDecimal.ROUND_HALF_UP).doubleValue();

        if (numDigits == 0) return new DataType(DataType.NUMBER, result.intValue());
        return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString());
    }

    @Override
    public DataType aggregation(Object... objects) {
        Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.AGGREGATION.getName());
        Double result = 0d;
        if (objects.length == 0 || objects.length < 2) {
            return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString());
        }
        List<Double> dataList = new ArrayList<Double>();
        for (int i = 0; i < objects.length - 1; i++) {
            boolean isArray = false;
            String paramType;
            Object objectData;
            if (objects[i] instanceof DataType) {
                DataType dataType1 = (DataType) objects[i];
                paramType = dataType1.getDataType();
                objectData = ExcelParamUtil.getParamContent(dataType1, "string");
            } else if (objects[i] instanceof Object[]) {
                Object[] arrayObjs = (Object[]) objects[i];
                String arrayType = null;
                objectData = "";
                for (Object arrayObj : arrayObjs) {
                    String lcoalType = "";
                    if (arrayObj instanceof DataType) {
                        lcoalType = ExcelParamUtil.getParamType(arrayObj);
                        objectData += ExcelParamUtil.getParamContent((DataType) arrayObj, "string") + "#";
                    } else {
                        lcoalType = ExcelParamUtil.getParamType(arrayObj.getClass().getName());
                        objectData += arrayObj + "#";
                    }
                    if (arrayType == null) {
                        arrayType = lcoalType;
                    } else {
                        if (!arrayType.equals(lcoalType)) {
                            JSONObject errorJson = ErrorUtil.buildError(FuncNames.AGGREGATION.toString(), errorNumber, errorNumber, "操作符参数类型不一致");
                            throw new RuntimeException(errorJson.getString("msg"));
                        }
                    }
                }
                paramType = arrayType;
                isArray = true;
            } else {
                paramType = ExcelParamUtil.getParamType(objects[i].getClass().getName());
                objectData = objects[i];
            }
            paramType = ExcelParamUtil.checkParamType(paramType);
            if (!paramType.equalsIgnoreCase(DataType.NUMBER)) {
                JSONObject errorJson = ErrorUtil.buildError(FuncNames.AGGREGATION.toString(), errorNumber, errorNumber, "统计函数只允许数字");
                throw new RuntimeException(errorJson.getString("msg"));
            }
            if (isArray) {
                String[] arrayStrs = objectData.toString().split("#");
                for (String arrayStr : arrayStrs) {
                    Double data = Double.parseDouble(arrayStr);
                    dataList.add(data);
                }
            } else {
                Double data = Double.parseDouble(objectData.toString());
                dataList.add(data);
            }

        }

        String aggType = objects[objects.length - 1].toString().toLowerCase();

        Collections.sort(dataList);
        switch (aggType) {
            case "avg":
                for (Double data : dataList) {
                    result += data;
                }
                result = result / dataList.size();
                break;
            case "max":
                result = dataList.get(dataList.size() - 1);
                break;
            case "min":
                result = dataList.get(0);
                break;
            default:
                JSONObject errorJson = ErrorUtil.buildError(FuncNames.AGGREGATION.toString(), errorNumber, errorNumber, "统计函数需要类型参数");
                throw new RuntimeException(errorJson.getString("msg"));
        }
        return new DataType(DataType.NUMBER, result, "ComponentType.NumberComponent".toString());
    }

    @Override
    public DataType mod(Object... objects) {
        Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.MOD.getName());
        if (objects.length != 2) {
            return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString());
        }

        Double doubleOne = 0d;
        Double doubleTwo = 0d;
        for (int i = 0; i < objects.length; i++) {
            Object paramObj = objects[i];
            String type;
            if (paramObj instanceof DataType) {
                DataType paramDataType = (DataType) paramObj;
                type = paramDataType.getDataType();
            } else {
                type = ExcelParamUtil.getParamType(paramObj.getClass().getName());
            }
            if (!type.equalsIgnoreCase(DataType.NUMBER)) {
                return new DataType(DataType.NUMBER, 0, "ComponentType.NumberComponent".toString());
            }
            if (i == 0) {
                doubleOne = Double.parseDouble(ExcelParamUtil.getParamContent(paramObj, "string").toString());
            } else {
                doubleTwo = Double.parseDouble(ExcelParamUtil.getParamContent(paramObj, "string").toString());
            }
        }


        Double value = doubleOne % doubleTwo;
        return new DataType(DataType.NUMBER, value, "ComponentType.NumberComponent".toString());
    }

    @Override
    public DataType Trunc(Object number, Object numDigits) {
        Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.TRUNC.getName());
        Object f1 = 0;
        Object numberVal;
        Object digitsVal;
        if (number instanceof DataType) {
            numberVal = ExcelParamUtil.getParamContent(number, "");
        } else {
            numberVal = number;
        }

        if (numDigits instanceof DataType) {
            digitsVal = ExcelParamUtil.getParamContent(numDigits, "");
        } else {
            digitsVal = numDigits;
        }

        if (RegularUtil.isNumber(numberVal) && RegularUtil.isNumber(digitsVal)) {
            Double d = Double.parseDouble(digitsVal.toString());
            int digitsIntVal = d.intValue();
            if (digitsIntVal > 5) {
                digitsIntVal = 5;
            }
            BigDecimal b = new BigDecimal(numberVal.toString());
            f1 = b.setScale(digitsIntVal, BigDecimal.ROUND_HALF_UP).doubleValue();
            if (digitsIntVal == 0) {
                f1 = b.intValue();
            }
        } else {
            JSONObject errorJson = ErrorUtil.buildError(FuncNames.TRUNC.toString(), errorNumber, errorNumber, "小数点格式化只允许数字");
            throw new RuntimeException(errorJson.getString("msg"));
        }
        return new DataType(DataType.NUMBER, f1, "ComponentType.NumberComponent".toString());
    }

    @Override
    public DataType randomNumber(Object length, Object type) {
        String value = "";
        Integer errorNumber = IgnoreParamFilter.getSetFuncNumber(FuncNames.RANDOMNUMBER.getName());
        Double numberLength = 0.0;
        Object param = 10;
        String dataValueType = "";
        if (length != null) {
            if (length instanceof DataType) {
                DataType dataType = (DataType) length;
                dataValueType = ExcelParamUtil.checkParamType(dataType);
                param = ExcelParamUtil.getParamContent(length, "");
            } else {
                dataValueType = ExcelParamUtil.checkParamType(length);
                param = length;
            }
        }
        //判断length长度数据类型是否合规
        if (!dataValueType.equalsIgnoreCase("number")) {
            JSONObject errorJson = ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(), errorNumber, errorNumber, "随机数函数只允许数字参数");
            throw new RuntimeException(errorJson.getString("msg"));
        }
        //判断用户设置的length是否大于0，生成的随机数长度必须是大于1的
        if (param != null) {
            numberLength = Double.parseDouble(param.toString());
            if (numberLength <= 0) {
                JSONObject errorJson = ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(), errorNumber, errorNumber, "随机数函数长度必须大于0");
                throw new RuntimeException(errorJson.getString("msg"));
            }
        }

        String typeString = randomNumber;
        if (type != null) {
            if (type instanceof DataType) {
                DataType dataType = (DataType) length;
                typeString = ExcelParamUtil.getParamContent(type, "").toString();
            } else {
                typeString = type.toString();
            }
        }

        switch (typeString) {
            case randomNumber:
                value = randomFunc(numberLength, randomNumber);
                break;
            case randomChar:
                value = randomFunc(numberLength, randomChar);
                break;
            case randomNumANDChar:
                value = randomFunc(numberLength, randomNumANDChar);
                break;
            default:
                JSONObject errorJson = ErrorUtil.buildError(FuncNames.RANDOMNUMBER.toString(), errorNumber, errorNumber, "随机数的返回值只允许数字、字符以及数字和字符的混合类型");
                throw new RuntimeException(errorJson.getString("msg"));

        }

        return new DataType(DataType.NUMBER, value, "ComponentType.NumberComponent".toString());
    }

    @Override
    public DataType group(Object... objects) {
        return null;
    }

    @Override
    public DataType isInt(Object... objects) {
        boolean isInt = false;
        if (objects[0] instanceof DataType) {
            DataType dataType = (DataType) objects[0];
            isInt = RegularUtil.isInteger(dataType.getContent());
        } else {
            isInt = RegularUtil.isInteger(objects[0]);
        }
        return new DataType(DataType.BOOL, isInt);
    }

    @Override
    public DataType isNumber(Object... objects) {
        boolean isInt = false;
        if (objects[0] instanceof DataType) {
            DataType dataType = (DataType) objects[0];
            isInt = RegularUtil.isNumber(dataType.getContent());
        } else {
            isInt = RegularUtil.isNumber(objects[0]);
        }
        return new DataType(DataType.BOOL, isInt);
    }

    private String randomFunc(Double length, String type) {
        Random r = new Random();
        StringBuffer sbff = new StringBuffer();

        //数字类型随机数
        if (type.equalsIgnoreCase("number")) {
            for (double i = 0; i < length; i++) {
                sbff.append(r.nextInt(10));
            }
            return sbff.toString();
            //英文字母类型随机数
        } else if (type.equalsIgnoreCase("char")) {
            for (double i = 0; i < length; i++) {
                int charInt = r.nextInt(26) + 'A';
                sbff.append((char) charInt);
            }
            return sbff.toString();
            //组合类型随机数
        } else {
            //如果长度等于1，就不适合做数字字符随机数组合，将长度改为2
            double numloop = 1;
            double charloop = 1;
            if (length == 1) {
                length = 2.0;
            } else {
                //如果长度是奇数
                if (length % 2 > 0) {
                    charloop = (length - 1) / 2;
                    numloop = charloop + 1;
                } else {
                    charloop = length / 2;
                    numloop = charloop;
                }
            }
            for (double i = 0; i < charloop; i++) {
                int charInt = r.nextInt(26) + 'a';
                sbff.append((char) charInt);
            }
            String charRandom = sbff.toString();
            sbff.setLength(0);
            sbff.append(charRandom);
            for (double i = 0; i < numloop; i++) {
                sbff.append(r.nextInt(10));
            }

            return sbff.toString();
        }
    }

}
