package com.syjy.calculate.service;

import com.googlecode.aviator.AviatorEvaluator;
import com.syjy.calculate.entity.*;
import com.syjy.calculate.repository.CalculationFormulaRepository;
import com.syjy.calculate.util.Common;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.*;

/**
 * 计算准确率、合格率
 *
 * @author zcl
 * @version 1.0
 * @since 2022/8/8 9:30
 */
@Service
@Slf4j
public class AssessmentCalculateService {

    @Autowired
    private CalculationFormulaRepository calculationFormulaRepository;

    @Autowired
    private Common common;

    /**
     * 计算考核电量
     *
     * @return
     */
    public CalculateResult calculateAssessment(AssessmentRequest assessmentRequest) {
        log.info("--------------------考核计算开始--------------------");
        AssessmentInfo assessmentInfo = new AssessmentInfo();
        CalculateResult checkResult = checkRequestInfo(assessmentRequest);
        // 如果校验失败
        if (!String.valueOf(checkResult.get(CalculateResult.CODE_TAG)).equals(CalculateResult.Type.SUCCESS.value())) {
            return checkResult;
        }
//        // 上下文
//        Map<String, Object> env = new HashMap<>();
//        BeanMap map = BeanMap.create(assessmentRequest);
//        // 将考核bean转为map
//        for (Object key : map.keySet()) {
//            env.put(String.valueOf(key), map.get(key));
//        }

        // 将实体类转为Map
        Map<String, Object> env = common.beanToMap(assessmentRequest);

        // 中期上报率
        String midReportRate = calculateDetail(assessmentRequest, env, CalculateResult.MID_REPORT_RATE);
        // 短期上报率
        String shortReportRate = calculateDetail(assessmentRequest, env, CalculateResult.SHORT_REPORT_RATE);
        // 超短期上报率
        String ultraShortReportRate = calculateDetail(assessmentRequest, env, CalculateResult.ULTRA_SHORT_REPORT_RATE);
        // 中期准确率
        String midAccuracyRate = calculateDetail(assessmentRequest, env, CalculateResult.MID_ACCURACY_RATE);
        // 短期准确率
        String shortAccuracyRate = calculateDetail(assessmentRequest, env, CalculateResult.SHORT_ACCURACY_RATE);
        // 超短期准确率
        String ultraShortAccuracyRate = calculateDetail(assessmentRequest, env, CalculateResult.ULTRA_SHORT_ACCURACY_RATE);
        // 短期合格率
        String shortPassRate = calculateDetail(assessmentRequest, env, CalculateResult.SHORT_PASS_RATE);
        // 超短期合格率
        String ultraShortPassRate = calculateDetail(assessmentRequest, env, CalculateResult.ULTRA_SHORT_PASS_RATE);
        // 单机信息可用率
        String singleMachinePassRate = calculateDetail(assessmentRequest, env, CalculateResult.SINGLE_MACHINE_PASS_RATE);
        // 可用发电功率可用率
        String ablePowerAccuracyRate = calculateDetail(assessmentRequest, env, CalculateResult.ABLE_POWER_ACCURACY_RATE);
        // 理论发电功率可用率
        String theoryPowerAccuracyRate = calculateDetail(assessmentRequest, env, CalculateResult.THEORY_POWER_ACCURACY_RATE);
        // 测风塔/气象站可用率
        String anemometerTowerAccuracyRate = calculateDetail(assessmentRequest, env, CalculateResult.ANEMOMETER_TOWER_ACCURACY_RATE);
        // 装机容量可用率
        String installedCapacityAccuracyRate = calculateDetail(assessmentRequest, env, CalculateResult.INSTALLED_CAPACITY_ACCURACY_RATE);
        // 可用容量可用率
        String availableCapacityAccuracyRate = calculateDetail(assessmentRequest, env, CalculateResult.AVAILABLE_CAPACITY_ACCURACY_RATE);

        assessmentInfo.setMidReportRate(midReportRate);
        assessmentInfo.setShortReportRate(shortReportRate);
        assessmentInfo.setUltraShortReportRate(ultraShortReportRate);
        assessmentInfo.setMidAccuracyRate(midAccuracyRate);
        assessmentInfo.setShortAccuracyRate(shortAccuracyRate);
        assessmentInfo.setUltraShortAccuracyRate(ultraShortAccuracyRate);
        assessmentInfo.setShortPassRate(shortPassRate);
        assessmentInfo.setUltraShortPassRate(ultraShortPassRate);
        assessmentInfo.setSingleMachinePassRate(singleMachinePassRate);
        assessmentInfo.setAblePowerAccuracyRate(ablePowerAccuracyRate);
        assessmentInfo.setTheoryPowerAccuracyRate(theoryPowerAccuracyRate);
        assessmentInfo.setAnemometerTowerAccuracyRate(anemometerTowerAccuracyRate);
        assessmentInfo.setInstalledCapacityAccuracyRate(installedCapacityAccuracyRate);
        assessmentInfo.setAvailableCapacityAccuracyRate(availableCapacityAccuracyRate);
        log.info("--------------------考核计算结束--------------------");
        return CalculateResult.success(CalculateResult.MSG_CALCULATE_SUCCESS, assessmentInfo);

    }

    /**
     * 校验请求参数
     *
     * @param assessmentRequest
     * @return
     */
    private CalculateResult checkRequestInfo(AssessmentRequest assessmentRequest) {

        // 判断入参
        if (assessmentRequest == null) {
            return CalculateResult.error(CalculateResult.MSG_REQUEST_NULL);
        }

        // 判断省调
        if (assessmentRequest.getProvince() == null) {
            return CalculateResult.error(CalculateResult.MSG_PROVINCE_NULL);
        }

        // 判断场站类型
        if (assessmentRequest.getElectricType() == null) {
            return CalculateResult.error(CalculateResult.MSG_ELECTRIC_TYPE_NULL);
        }
        return CalculateResult.success();
    }

    /**
     * 各项考核计算
     *
     * @return
     */
    private String calculateDetail(AssessmentRequest assessmentRequest, Map<String, Object> env, String formulaType) {

        // 根据类型从数据库中查出考核公式列表
        CalculationFormula calculationFormula = calculationFormulaRepository.findAssessmentByTypeAndProvince(CalculateResult.FORMULA, formulaType, assessmentRequest.getProvince(), assessmentRequest.getElectricType(), assessmentRequest.getStationCode());
        // 判断是否有公式
        if (calculationFormula == null || calculationFormula.getFormula() == null) {
            // 未匹配到公式
            log.info(assessmentRequest.getProvince() + "-" + assessmentRequest.getStationCode() + CalculateResult.LINE + formulaType + CalculateResult.COLON + CalculateResult.MSG_NO_FORMULA);
            return CalculateResult.MSG_ERROR;
        }
        // 根据类型从数据库中查出规则列表
        CalculationFormula rulesCalculationFormula = calculationFormulaRepository.findAssessmentByTypeAndProvince(CalculateResult.RULES, formulaType, assessmentRequest.getProvince(), assessmentRequest.getElectricType(), assessmentRequest.getStationCode());

        // 判断是否有约束
        if (rulesCalculationFormula != null && rulesCalculationFormula.getFormula() != null) {
            // 校验规则
            String checkResult = calculate(env, rulesCalculationFormula.getFormula(), assessmentRequest.getProvince(), formulaType, assessmentRequest.getElectricType(), CalculateResult.RULES);
            // 如果校验失败，返回失败原因
            if (!checkResult.equals(CalculateResult.MSG_CHECK_SUCCESS)) {
                log.info(CalculateResult.MSG_CHECK_FAIL + assessmentRequest.getProvince() + "-" + assessmentRequest.getStationCode() + CalculateResult.LINE + formulaType + CalculateResult.COLON + checkResult);
                return CalculateResult.MSG_ERROR;
            }
        }
        // 计算考核
        String result = this.calculate(env, calculationFormula.getFormula(), assessmentRequest.getProvince(), formulaType, assessmentRequest.getElectricType(), CalculateResult.FORMULA);
        return result;
    }

    /**
     * 计算
     *
     * @param env
     * @param formulaContent
     * @param province
     * @param formulaType
     * @param electricType
     * @param calculateType
     * @return
     */
    private String calculate(Map<String, Object> env, String formulaContent, String province, String formulaType, String electricType, String calculateType) {
        // 获取公式缓存名称
        String scriptName = common.initFormula(formulaContent, province, formulaType, electricType, calculateType);
        try {
            // 根据公式和上下文进行计算
            Object executeResult = AviatorEvaluator.getInstance().getCachedExpressionByKey(scriptName).execute(env);
            // 如果是校验规则
            if (calculateType.equals(CalculateResult.RULES)) {
                Map<String, Object> checkResult = (HashMap<String, Object>) executeResult;
                // 如果返回500，则为校验不通过，返回原因
                if (String.valueOf(checkResult.get(CalculateResult.CODE_TAG)).equals(CalculateResult.ERROR)) {
                    return String.valueOf(checkResult.get(CalculateResult.MSG_TAG));
                }
                // 校验成功
                return CalculateResult.MSG_CHECK_SUCCESS;
                // 如果是计算，则返回计算结果
            } else if (calculateType.equals(CalculateResult.FORMULA)) {
                return String.valueOf(executeResult);
            } else {
                // 计算类型错误，计算类型必须是RULES或者FORMULA
                return CalculateResult.MSG_NO_CALCULATE_TYPE;
            }
        } catch (Exception e) {
            e.printStackTrace();
            return CalculateResult.MSG_CALCULATE_FAIL + e.toString();
        }
    }

}

