package jtznyj.engineer.service.dataDiagnosticService;

import cn.hutool.core.date.DateUtil;
import jtznyj.engineer.service.winform.data.MonitorContext;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import jtznyj.engineer.service.dataDiagnosticService.data.AlarmPoint;
import jtznyj.engineer.service.dataDiagnosticService.data.DrillState;
import jtznyj.engineer.service.dataDiagnosticService.models.DoorList;

import java.text.DecimalFormat;
import java.util.Date;
import java.util.Hashtable;

import static jtznyj.engineer.service.winform.CheckEngineerWarning.getRealFieldName;

/**
 * 单井趋势--门限诊断
 */
@Slf4j
public class WellMinMaxTrendDataDiagnostic extends WellTrendDataDiagnostic {
    /**
     * 单一模型诊断分析
     *
     * @param record
     * @param currentPumpState
     * @param drillState
     * @param lastPumpRunTime
     * @param lastPumpStopTime
     * @return
     */
    @Override
    protected DataDiagnosticAnalyzeResult internalAnalyse(Hashtable record, boolean currentPumpState, DrillState drillState, Date lastPumpRunTime, Date lastPumpStopTime) {
        DataDiagnosticAnalyzeResult analyseResult = this.beforeAnalyse(record, currentPumpState, drillState, lastPumpRunTime, lastPumpStopTime);
        if (!analyseResult.result) {
            //提前退出--不报警
            analyseResult.result = false;
            return analyseResult;
        }

        analyseResult.result = false;

        //判断前置条件
        if (this.param._preconditions && StringUtils.isNotEmpty(this.param._preconditionsField) && this.param._doorList.size() > 0) {
            int iCount = this.param._doorList.size();
            double conditionValue = (double) record.get(getRealFieldName(this.param._preconditionsField));
            double rValue = (double) record.get(this.param._originalField);

            boolean boolzf, boolbfb, boolqj;//百分比、振幅条件、普通区间[0,1200]
            DoorList curDoorList;
            if (conditionValue != DOUBLE_NULL_VALUE && rValue != DOUBLE_NULL_VALUE) {
                for (int i = 0; i < iCount; i++) {
                    curDoorList = this.param._doorList.get(i);
                    //在指定的范围区间
                    if (conditionValue > curDoorList.preconditionMin && conditionValue <= curDoorList.preconditionMax) {
                        if (rValue > curDoorList.ruleMin && rValue <= curDoorList.ruleMax) {
                            return analyseResult;
                        }

                        if (!curDoorList.isAmplification && !curDoorList.isPercentage) {
                            continue;
                        }
                        //振幅
                        boolzf = (curDoorList.isAmplification && (curDoorList.ruleMin - rValue) > Math.abs(curDoorList.amplification)) ||
                                (curDoorList.isAmplification && (rValue - curDoorList.ruleMax) > Math.abs(curDoorList.amplification));
                        //百分比
                        boolbfb = curDoorList.isPercentage && Math.abs(curDoorList.ruleMax - rValue) > curDoorList.ruleMax * curDoorList.percentage / 100.0;
                        boolqj = (!curDoorList.isPercentage) && (!curDoorList.isAmplification) && ((curDoorList.ruleMax - rValue > 0));
                        if (boolzf || boolbfb) {
                            AlarmPoint description = new AlarmPoint();
                            description.name = this.param._name;
                            description.field = this.param._realField;
                            description.alarmType = this.param._analyseType.toString();
                            //description._dtStart = tvMinMax0.getDateTime();
                            //description.alarmDate = new Date(record.get().getTime());
                            //description._startValue = tvMinMax0.getValue();
                            description.value = rValue;
                            description.alarmDate = (Date) record.get(MonitorContext.fieldTime);
                            //description._startDepth = getWellDepth(tvMinMax0.getData());
                            //description._startZtDepth = getDrillDepth(tvMinMax0.getData());
                            description.depth = getWellDepth(record);
                            description.ztDepth = getDrillDepth(record);

                            description.des = this.setPreDescription("", description, curDoorList, conditionValue);


                            this._secondState.SetAlarm(true);
                            //description._secondState = this._secondState.Clone();
                            description.WarningCause = setWarningCause(description);

                            analyseResult.result = true;
                            analyseResult.description = description;
                            log.debug(" {}, 数据趋势minMaxTrend,条件值{},ltd记录值{}",
                                    DataDiagnosticEngineer.packStackStr(Thread.currentThread().getStackTrace()),
                                    conditionValue, this.param._originalField + " " + rValue);
                            return analyseResult;
                        }

                        return analyseResult;
                    }
                }
                analyseResult.result = false;
                return analyseResult;
            }
        }
        int iCount = this.trendDataList.size();
        if (iCount < 2) {
            return analyseResult;
        }

        //================================================
        //门限分析--begin
        //double dValue = 0.0;
        double dAllSec = 0.0;
        double _continuedTime = Math.max(0, this.param._continuedTime);
        TimeValuePair<Hashtable> tvMinMax0 = null;
        TimeValuePair<Hashtable> tvMinMax = null;
        TimeValuePair<Hashtable> tvStep = this.trendDataList.get(0);//第一个点
        TimeValuePair<Hashtable> currentTimeValue = null;
        tvMinMax0 = tvStep;
        for (int i = 1; i < this.trendDataList.size(); i++) {
            currentTimeValue = this.trendDataList.get(i);

            if (currentTimeValue.getValue() > this.param._maxTotalNum || currentTimeValue.getValue() < this.param._minTotalNum) {
                //区间之外属于异常情况
//                if (prevTimeValue == null) {
//                    tvMinMax0 = tvStep;
//                }
                tvMinMax = this.trendDataList.get(i);
                dAllSec += (int) (Math.abs(currentTimeValue.getDateTime().getTime() - this.trendDataList.get(i - 1).getDateTime().getTime()) / 1000);
                if (dAllSec > _continuedTime) {
                    //如果超过了异常持续时间，直接退出循环
                    break;
                }
            } else {
                dAllSec = 0.0;
                //从头开始计算异常起始点
                tvMinMax0 = currentTimeValue;
            }
        }
        //异常时长与持续时长比值
        analyseResult.percent = dAllSec / this.param._continuedTime;
        if (this.trendDataList.size() > 0) {
            //此段代码可以放在最终的报警的代码域
            this._secondState.SetMinMax(this.trendDataList.get(0).getDateTime(), this.trendDataList.get(this.trendDataList.size() - 1).getDateTime(),
                    this.param._minTotalNum, this.param._maxTotalNum, currentTimeValue.getValue());
        }

        //门限分析关键的判断条件，得出结论--必须确持续时间大于0
        if (this.trendDataList.size() > 0 && dAllSec > _continuedTime && null != tvMinMax) {
            AlarmPoint description = new AlarmPoint();
            description.name = this.param._name;
            description.field = this.param._realField;
            description.alarmType = this.param._analyseType.toString();
            //description._dtStart = tvMinMax0.getDateTime();
            description.alarmDate = new Date(tvMinMax.getDateTime().getTime());
            //description._startValue = tvMinMax0.getValue();
            description.value = tvMinMax.getValue();
            //description._startDepth = getWellDepth(tvMinMax0.getData());
            //description._startZtDepth = getDrillDepth(tvMinMax0.getData());
            description.depth = getWellDepth(tvMinMax.getData());
            description.ztDepth = getDrillDepth(tvMinMax.getData());
            description.des = this.setDes("", description);

            this._secondState.SetAlarm(true);
            //description._secondState = this._secondState.Clone();
            description.WarningCause = setWarningCause(description);

            analyseResult.result = true;
            analyseResult.description = description;
            log.debug(" {}, 数据趋势minMaxTrend 判断2,时间位置{},持续时间(s){}",
                    DataDiagnosticEngineer.packStackStr(Thread.currentThread().getStackTrace()),
                    currentTimeValue, currentTimeValue);
            return analyseResult;
        }
        //门限分析--end
        //================================================

        return analyseResult;
    }

    /**
     * 设置报警描述信息--不带前置条件
     *
     * @param jh
     * @param description
     * @return
     */
    private String setDes(String jh, AlarmPoint description) {

        DecimalFormat decimalFormat = new DecimalFormat("###################.###########");
        DecimalFormat valueDf = new DecimalFormat("0.00");

        String des = "";
        des += "[" + this.jh + " " + description.name + "]";
        des += "\n";
        des += "时间: " + DateUtil.format(description.alarmDate, "yyyy-MM-dd HH:mm:ss");
        des += "\n";
        des += "深度段: " + description.depth;
        des += "\n";
        des += "异常原因: " + DataDiagnosticEngineer.getRealFieldName(description.field) + " 超出门限设置("
                + decimalFormat.format(this.param._minTotalNum) + "-" + decimalFormat.format(this.param._maxTotalNum)
                + this.param._unit + "),当前值" + valueDf.format(description.value) + this.param._unit;
        ;
        return des;
    }

    /**
     * 设置报警描述信息--带前置条件报警
     *
     * @param s
     * @param description
     * @param curDoorList
     * @param conditionValue
     * @return
     */
    protected String setPreDescription(String s, AlarmPoint description, DoorList curDoorList, double conditionValue) {
        DecimalFormat decimalFormat = new DecimalFormat("###################.###########");
        DecimalFormat valueDf = new DecimalFormat("0.00");

        String des = "";
        des += "[" + this.jh + " " + description.name + "]";
        des += "\n";
        des += "时间: " + DateUtil.format(description.alarmDate, "yyyy-MM-dd HH:mm:ss");
        des += "\n";
        des += "深度段: " + description.depth;
        des += "\n";
        des += "异常原因: " + DataDiagnosticEngineer.getRealFieldName(this.param._preconditionsField)
                + conditionValue + DataDiagnosticEngineer.getFieldUnit(this.param._preconditionsField) + ",";
        des += DataDiagnosticEngineer.getRealFieldName(this.param._originalField) + valueDf.format(description.value)
                + DataDiagnosticEngineer.getFieldUnit(this.param._originalField)
                + "超过设定值[" + decimalFormat.format(curDoorList.ruleMin)
                + DataDiagnosticEngineer.getFieldUnit(this.param._originalField) + ","
                + decimalFormat.format(curDoorList.ruleMax)
                + DataDiagnosticEngineer.getFieldUnit(this.param._originalField) + "]";
        boolean boolbfb, boolzf;
        boolzf = (curDoorList.isAmplification && (curDoorList.ruleMin - description.value) > Math.abs(curDoorList.amplification)) ||
                (curDoorList.isAmplification && (curDoorList.ruleMax - description.value) > Math.abs(curDoorList.amplification));
        boolbfb = curDoorList.isPercentage && (curDoorList.ruleMax - description.value) > curDoorList.ruleMax * curDoorList.percentage / 100.0;
        if (curDoorList.isAmplification && boolzf) {
            des += "(+" + decimalFormat.format(curDoorList.amplification) + DataDiagnosticEngineer.getFieldUnit(this.param._originalField) + ")";
        } else if (curDoorList.isPercentage && boolbfb) {
            des += "(+" + decimalFormat.format(curDoorList.preconditionMax) + "%)";
        }
        this._secondState._valueMin = curDoorList.ruleMin;
        this._secondState._valueMax = curDoorList.ruleMax;
        this._secondState._value0 = description.value;
        return des;
    }

    private String setWarningCause(AlarmPoint description) {
        DecimalFormat decimalFormat = new DecimalFormat("###################.###########");
        DecimalFormat valueDf = new DecimalFormat("0.00");

        return "异常原因: " + DataDiagnosticEngineer.getRealFieldName(description.field) + " 超出门限设置("
                + decimalFormat.format(this.param._minTotalNum) + "-" + decimalFormat.format(this.param._maxTotalNum)
                + this.param._unit + ")";
    }

}
