package org.eco.als.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import com.ql.util.express.DefaultContext;
import com.ql.util.express.ExpressRunner;
import com.ql.util.express.InstructionSet;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.eco.als.domain.bo.ExpressBo;
import org.eco.als.service.IFormulaService;
import org.eco.als.utils.CheckVibrationDuration;
import org.eco.als.utils.CsvUtils;
import org.eco.common.core.constant.Constants;
import org.eco.common.core.exception.BusinessException;
import org.eco.common.core.utils.StringUtils;
import org.eco.system.domain.vo.SysOssVo;
import org.eco.system.service.ISysOssService;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author wanggaokun
 */
@Service
@Slf4j
public class FormulaService implements IFormulaService {
    @Resource
    private ISysOssService ossService;
    private ExpressRunner runner;

    @Override
    public JSONObject evaluateExpression(ExpressBo expressBo) {
        // 虚警
        int result = 1;
        String timeFlag = null;
        JSONObject resultJson = new JSONObject();
        try {
//            CsvUtils.getCsvHeaders("");
            runner = new ExpressRunner();
            runner.addOperatorWithAlias("≠", "!=", null);
            runner.addOperatorWithAlias("≥", ">=", null);
            runner.addOperatorWithAlias("≤", "<=", null);
            // // 注册自定义(持续时间计算)函数到QLExpress上下文
            runner.addFunction("checkVibrationDuration", new CheckVibrationDuration());
            runner.setShortCircuit(true);
            runner.parseInstructionSet(expressBo.getExpression());
            SysOssVo ossVo = ossService.getById(expressBo.getOssId());
            String path = StringUtils.substringAfter(ossVo.getFileName(), Constants.RESOURCE_PREFIX);

            // 参数列名称
            List<String> headers = CsvUtils.getCsvHeaders(path);
            String[] variableNames = parseVariableNames(expressBo.getExpression());
            if (!CollUtil.containsAll(headers, Arrays.asList(variableNames))) {
                log.info("参数列名称匹配不成功:{}{}", Arrays.toString(variableNames), headers.toString());
                resultJson.set("result", result);
                return resultJson;
            }

            JSONArray arr = CsvUtils.fileCsvToJsonRegex(path);
            for (Object object : arr) {
                DefaultContext<String, Object> context = new DefaultContext<>();
                Map<String, Object> variables = CollUtil.isEmpty(expressBo.getVariables()) ? buildVariableContext(expressBo, (JSONObject) object) : expressBo.getVariables();
                context.putAll(variables);
                Boolean isMatch = (Boolean) runner.execute(expressBo.getExpression(), context, null, true, false);
                log.info("isMatch==========================:{}", isMatch);
                if (isMatch) {
                    timeFlag = ((JSONObject) object).getStr("时间");
                    // 实警
                    result = 0;
                    break;
                }
            }
        } catch (Exception e) {
            throw new BusinessException(e.getMessage());
        }
        resultJson.set("timeFlag", timeFlag);
        resultJson.set("result", result);
        return resultJson;
    }

    private Map<String, Object> buildVariableContext(ExpressBo expressBo, JSONObject jsonObject) {
        String[] variableNames = parseVariableNames(expressBo.getExpression());
        Map<String, Object> variables = new HashMap<>();
        // 字段属性自定义值
        for (String fieldName : variableNames) {
            if(StrUtil.equals("时间", fieldName)) {
                variables.put(fieldName, jsonObject.get(fieldName));
            } else {
                variables.put(fieldName, Double.parseDouble((String) jsonObject.get(fieldName)));
            }
        }
        return variables;
    }

    /**
     * 解析表达式中的变量名。
     */
    private String[] parseVariableNames(String expression) {
        try {
            InstructionSet instructions = runner.parseInstructionSet(expression);
            return instructions.getOutAttrNames();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
