package com.njcn.gather.tool.adddata.component;

import com.njcn.gather.tool.adddata.pojo.bo.AddDataTableDefinition;
import org.springframework.stereotype.Component;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.sql.Timestamp;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.SplittableRandom;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 电能质量数据生成器。
 */
@Component
public class AddDataValueGenerator {

    /** 谐波列匹配。 */
    private static final Pattern HARMONIC_PATTERN = Pattern.compile("^([VIQPS])_(\\d+)$");

    /** 基础列后缀。 */
    private static final String SUFFIX_MAX = "_MAX";
    private static final String SUFFIX_MIN = "_MIN";
    private static final String SUFFIX_CP95 = "_CP95";

    /** 两倍 PI。 */
    private static final double TWO_PI = Math.PI * 2D;

    /**
     * 生成一行落库值。
     *
     * @param definition 表定义
     * @param lineId 监测点 ID
     * @param timeId 时间点
     * @param phaseCode 相别
     * @return 与字段顺序一致的值列表
     */
    public List<Object> generateRow(AddDataTableDefinition definition, String lineId, LocalDateTime timeId, String phaseCode) {
        MeasurementState state = buildState(lineId, timeId, phaseCode);
        Map<String, Double> baseValues = buildBaseValues(definition, state);
        List<Object> row = new ArrayList<Object>(definition.getColumns().size());
        for (String column : definition.getColumns()) {
            if ("TIMEID".equals(column)) {
                row.add(Timestamp.valueOf(timeId));
                continue;
            }
            if ("LINEID".equals(column)) {
                row.add(lineId);
                continue;
            }
            if ("PHASIC_TYPE".equals(column)) {
                row.add(phaseCode);
                continue;
            }
            if ("QUALITYFLAG".equals(column)) {
                row.add(0);
                continue;
            }
            row.add(resolveColumnValue(definition.getTableName(), column, baseValues, state));
        }
        return row;
    }

    /**
     * 按列名解析字段值。
     *
     * @param tableName 表名
     * @param column 列名
     * @param baseValues 主值集合
     * @param state 基础状态
     * @return 对应值
     */
    private Double resolveColumnValue(String tableName, String column, Map<String, Double> baseValues, MeasurementState state) {
        if (baseValues.containsKey(column)) {
            return baseValues.get(column);
        }
        if (column.endsWith(SUFFIX_MAX)) {
            return deriveMetric(baseValues.get(removeSuffix(column, SUFFIX_MAX)), column, state, MetricType.MAX);
        }
        if (column.endsWith(SUFFIX_MIN)) {
            return deriveMetric(baseValues.get(removeSuffix(column, SUFFIX_MIN)), column, state, MetricType.MIN);
        }
        if (column.endsWith(SUFFIX_CP95)) {
            return deriveMetric(baseValues.get(removeSuffix(column, SUFFIX_CP95)), column, state, MetricType.CP95);
        }
        throw new IllegalStateException("未支持的 add-data 列：" + tableName + "." + column);
    }

    /**
     * 生成主值列集合。
     *
     * @param definition 表定义
     * @param state 基础状态
     * @return 主值集合
     */
    private Map<String, Double> buildBaseValues(AddDataTableDefinition definition, MeasurementState state) {
        Map<String, Double> values = new HashMap<String, Double>();
        for (String column : definition.getColumns()) {
            if (isInfrastructureColumn(column) || isDerivedColumn(column)) {
                continue;
            }
            values.put(column, resolveBaseMetric(definition.getTableName(), column, state));
        }
        return values;
    }

    /**
     * 解析基础主值。
     *
     * @param tableName 表名
     * @param column 列名
     * @param state 基础状态
     * @return 主值
     */
    private Double resolveBaseMetric(String tableName, String column, MeasurementState state) {
        Matcher matcher = HARMONIC_PATTERN.matcher(column);
        if (matcher.matches()) {
            String prefix = matcher.group(1);
            int order = Integer.parseInt(matcher.group(2));
            if ("V".equals(prefix)) {
                if ("data_harmrate_v".equals(tableName)) {
                    return resolveRatioPercent(state.vHarmonics[order], state.vHarmonics[1]);
                }
                return state.vHarmonics[order];
            }
            if ("I".equals(prefix)) {
                if ("data_harmrate_i".equals(tableName)) {
                    return resolveRatioPercent(state.iHarmonics[order], state.iHarmonics[1]);
                }
                if ("data_inharm_i".equals(tableName)) {
                    return state.iInharmonics[order];
                }
                return state.iHarmonics[order];
            }
            if ("P".equals(prefix)) {
                return state.pHarmonics[order];
            }
            if ("Q".equals(prefix)) {
                return state.qHarmonics[order];
            }
            if ("S".equals(prefix)) {
                return state.sHarmonics[order];
            }
        }

        switch (column) {
            case "RMS":
                return "data_v".equals(tableName) ? state.phaseVoltage : state.currentRms;
            case "RMSAB":
                return state.lineVoltageAB;
            case "RMSBC":
                return state.lineVoltageBC;
            case "RMSCA":
                return state.lineVoltageCA;
            case "VU_DEV":
                return state.vUpperDeviation;
            case "VL_DEV":
                return state.vLowerDeviation;
            case "FREQ":
                return state.frequency;
            case "FREQ_DEV":
                return state.frequencyDeviation;
            case "V_UNBALANCE":
                return state.vUnbalance;
            case "V_POS":
                return state.vPositive;
            case "V_NEG":
                return state.vNegative;
            case "V_ZERO":
                return state.vZero;
            case "V_THD":
                return state.vThd;
            case "I_UNBALANCE":
                return state.iUnbalance;
            case "I_POS":
                return state.iPositive;
            case "I_NEG":
                return state.iNegative;
            case "I_ZERO":
                return state.iZero;
            case "I_THD":
                return state.iThd;
            case "PF":
                return state.powerFactor;
            case "DF":
                return state.distortionFactor;
            case "P":
                return state.activePower;
            case "Q":
                return state.reactivePower;
            case "S":
                return state.apparentPower;
            case "FLUC":
                return state.fluc;
            case "PST":
                return state.pst;
            case "PLT":
                return state.plt;
            case "FLUCCF":
                return state.flucCf;
            default:
                throw new IllegalStateException("未支持的基础指标列：" + tableName + "." + column);
        }
    }

    /**
     * 生成主值派生指标。
     *
     * @param baseValue 主值
     * @param column 派生列名
     * @param state 基础状态
     * @param metricType 派生类型
     * @return 派生值
     */
    private Double deriveMetric(Double baseValue, String column, MeasurementState state, MetricType metricType) {
        if (baseValue == null) {
            throw new IllegalStateException("派生字段缺少主值：" + column);
        }
        String baseColumn = resolveDerivedBaseColumn(column, metricType);
        double factor = noise(state.sharedSeed + baseColumn.hashCode(), 0.01D, 0.05D);
        double delta = Math.max(Math.abs(baseValue) * factor, 0.005D);
        double value;
        if (MetricType.MAX.equals(metricType)) {
            value = baseValue + delta;
        } else if (MetricType.MIN.equals(metricType)) {
            value = baseValue - delta;
            if (baseValue >= 0D) {
                value = Math.max(0D, value);
            }
        } else {
            value = baseValue + delta * 0.6D;
        }
        return round(value, 4);
    }

    private String resolveDerivedBaseColumn(String column, MetricType metricType) {
        if (MetricType.MAX.equals(metricType)) {
            return removeSuffix(column, SUFFIX_MAX);
        }
        if (MetricType.MIN.equals(metricType)) {
            return removeSuffix(column, SUFFIX_MIN);
        }
        return removeSuffix(column, SUFFIX_CP95);
    }

    /**
     * 构建同源基础状态。
     *
     * @param lineId 监测点 ID
     * @param timeId 时间
     * @param phaseCode 相别
     * @return 基础状态
     */
    private MeasurementState buildState(String lineId, LocalDateTime timeId, String phaseCode) {
        long sharedSeed = Objects.hash(lineId, timeId.getYear(), timeId.getDayOfYear(), timeId.getHour(), timeId.getMinute());
        long phaseSeed = Objects.hash(sharedSeed, phaseCode);
        double minuteOfDay = timeId.getHour() * 60D + timeId.getMinute();
        double dayWave = Math.sin(minuteOfDay / 1440D * TWO_PI);
        double fastWave = Math.cos(minuteOfDay / 240D * TWO_PI);
        double phaseWave = Math.sin(minuteOfDay / 1440D * TWO_PI + resolvePhaseOffset(phaseCode));

        double phaseVoltage = round(220D + dayWave * 3.6D + phaseWave * 1.5D + noise(phaseSeed + 11L, -0.9D, 0.9D), 4);
        double lineVoltageAB = round(380D + dayWave * 4.8D + noise(sharedSeed + 21L, -1.2D, 1.2D), 4);
        double lineVoltageBC = round(381D + fastWave * 3.6D + noise(sharedSeed + 22L, -1.2D, 1.2D), 4);
        double lineVoltageCA = round(379D + Math.sin(minuteOfDay / 720D * TWO_PI) * 4.2D + noise(sharedSeed + 23L, -1.2D, 1.2D), 4);
        double frequency = round(50D + Math.sin(minuteOfDay / 180D * TWO_PI) * 0.03D + noise(sharedSeed + 31L, -0.01D, 0.01D), 4);
        double frequencyDeviation = round(frequency - 50D, 4);

        double currentRms = round(85D + fastWave * 12D + phaseWave * 6D + noise(phaseSeed + 41L, -2D, 2D), 4);
        double vPositive = round(phaseVoltage * (0.992D + noise(sharedSeed + 51L, -0.003D, 0.003D)), 4);
        double vNegative = round(Math.max(0D, phaseVoltage * (0.008D + noise(phaseSeed + 52L, 0D, 0.006D))), 4);
        double vZero = round(Math.max(0D, phaseVoltage * (0.006D + noise(phaseSeed + 53L, 0D, 0.004D))), 4);
        double vUnbalance = resolveRatioPercent(vNegative, vPositive);
        double vUpperDeviation = round(Math.max((phaseVoltage - 220D) / 220D * 100D, 0D), 4);
        double vLowerDeviation = round(Math.max((220D - phaseVoltage) / 220D * 100D, 0D), 4);

        double iPositive = round(currentRms * (0.986D + noise(sharedSeed + 61L, -0.003D, 0.003D)), 4);
        double iNegative = round(Math.max(0D, currentRms * (0.016D + noise(phaseSeed + 62L, 0D, 0.01D))), 4);
        double iZero = round(Math.max(0D, currentRms * (0.011D + noise(phaseSeed + 63L, 0D, 0.008D))), 4);
        double iUnbalance = resolveRatioPercent(iNegative, iPositive);

        double[] vHarmonics = new double[51];
        double[] iHarmonics = new double[51];
        double[] iInharmonics = new double[51];
        vHarmonics[1] = phaseVoltage;
        iHarmonics[1] = currentRms;
        iInharmonics[1] = round(currentRms * 0.06D, 4);
        for (int order = 2; order <= 50; order++) {
            double voltageRatio = (0.015D / order) * (1D + noise(sharedSeed + order, -0.35D, 0.35D));
            double currentRatio = (0.08D / Math.sqrt(order)) * (1D + noise(phaseSeed + order, -0.4D, 0.4D));
            vHarmonics[order] = round(Math.max(0D, phaseVoltage * voltageRatio), 4);
            iHarmonics[order] = round(Math.max(0D, currentRms * currentRatio), 4);
            iInharmonics[order] = round(Math.max(0D, iHarmonics[order] * noise(phaseSeed + order * 13L, 0.08D, 0.18D)), 4);
        }

        double vThd = round(resolveThd(vHarmonics), 4);
        double iThd = round(resolveThd(iHarmonics), 4);

        double[] pHarmonics = new double[51];
        double[] qHarmonics = new double[51];
        double[] sHarmonics = new double[51];
        double activePower = 0D;
        double reactivePower = 0D;
        double apparentPower = 0D;
        for (int order = 1; order <= 50; order++) {
            double apparent = Math.max(0D, round(vHarmonics[order] * iHarmonics[order] / 1000D, 4));
            double angle = 0.16D + order * 0.008D + noise(sharedSeed + order * 17L, -0.03D, 0.03D);
            double active = round(apparent * Math.cos(angle), 4);
            double reactive = round(apparent * Math.sin(angle), 4);
            pHarmonics[order] = active;
            qHarmonics[order] = reactive;
            sHarmonics[order] = round(Math.sqrt(active * active + reactive * reactive), 4);
            activePower += active;
            reactivePower += reactive;
            apparentPower += sHarmonics[order];
        }
        activePower = round(activePower, 4);
        reactivePower = round(reactivePower, 4);
        apparentPower = round(apparentPower, 4);
        double powerFactor = apparentPower == 0D ? 1D : round(clamp(activePower / apparentPower, -1D, 1D), 4);
        double distortionFactor = round(1D / Math.sqrt(1D + Math.pow(vThd / 100D, 2D) + Math.pow(iThd / 100D, 2D)), 4);

        double fluc = round(0.35D + Math.abs(dayWave) * 0.18D + noise(sharedSeed + 71L, -0.03D, 0.03D), 4);
        double pst = round(fluc * 1.12D + 0.08D + noise(sharedSeed + 72L, -0.02D, 0.02D), 4);
        double plt = round(Math.max(0.01D, pst * 0.92D + 0.05D + noise(sharedSeed + 73L, -0.02D, 0.02D)), 4);
        double flucCf = round(fluc * (0.96D + noise(sharedSeed + 74L, -0.03D, 0.03D)), 4);

        return new MeasurementState(sharedSeed, phaseVoltage, lineVoltageAB, lineVoltageBC, lineVoltageCA,
                frequency, frequencyDeviation, currentRms, vPositive, vNegative, vZero, vUnbalance,
                vUpperDeviation, vLowerDeviation, iPositive, iNegative, iZero, iUnbalance,
                vHarmonics, iHarmonics, iInharmonics, vThd, iThd, pHarmonics, qHarmonics, sHarmonics,
                activePower, reactivePower, apparentPower, powerFactor, distortionFactor, fluc, pst, plt, flucCf);
    }

    /**
     * 解析百分比。
     *
     * @param part 分子
     * @param total 分母
     * @return 百分比
     */
    private double resolveRatioPercent(double part, double total) {
        if (total == 0D) {
            return 0D;
        }
        return round(part / total * 100D, 4);
    }

    /**
     * 解析 THD。
     *
     * @param harmonics 谐波数组
     * @return thd 百分比
     */
    private double resolveThd(double[] harmonics) {
        if (harmonics[1] == 0D) {
            return 0D;
        }
        double sum = 0D;
        for (int order = 2; order < harmonics.length; order++) {
            sum += harmonics[order] * harmonics[order];
        }
        return Math.sqrt(sum) / harmonics[1] * 100D;
    }

    /**
     * 解析相别偏移角。
     *
     * @param phaseCode 相别
     * @return 偏移角
     */
    private double resolvePhaseOffset(String phaseCode) {
        if ("B".equals(phaseCode)) {
            return TWO_PI / 3D;
        }
        if ("C".equals(phaseCode)) {
            return TWO_PI / 3D * 2D;
        }
        return 0D;
    }

    /**
     * 生成稳定随机扰动。
     *
     * @param seed 种子
     * @param min 最小值
     * @param max 最大值
     * @return 扰动值
     */
    private double noise(long seed, double min, double max) {
        return min + (max - min) * new SplittableRandom(seed).nextDouble();
    }

    /**
     * 截断小数位。
     *
     * @param value 原始值
     * @param scale 保留位数
     * @return 处理后的值
     */
    private double round(double value, int scale) {
        if (Math.abs(value) < 0.0000001D) {
            return 0D;
        }
        return BigDecimal.valueOf(value).setScale(scale, RoundingMode.HALF_UP).doubleValue();
    }

    /**
     * 移除列后缀。
     *
     * @param column 列名
     * @param suffix 后缀
     * @return 主值列名
     */
    private String removeSuffix(String column, String suffix) {
        return column.substring(0, column.length() - suffix.length());
    }

    /**
     * 判断是否为系统字段。
     *
     * @param column 列名
     * @return true 表示系统字段
     */
    private boolean isInfrastructureColumn(String column) {
        return "TIMEID".equals(column) || "LINEID".equals(column) || "PHASIC_TYPE".equals(column) || "QUALITYFLAG".equals(column);
    }

    /**
     * 判断是否为派生列。
     *
     * @param column 列名
     * @return true 表示派生列
     */
    private boolean isDerivedColumn(String column) {
        return column.endsWith(SUFFIX_MAX) || column.endsWith(SUFFIX_MIN) || column.endsWith(SUFFIX_CP95);
    }

    /**
     * 数值类型。
     */
    private enum MetricType {
        /** 最大值。 */
        MAX,
        /** 最小值。 */
        MIN,
        /** cp95。 */
        CP95
    }

    /**
     * 数值约束。
     *
     * @param value 值
     * @param min 最小值
     * @param max 最大值
     * @return 限幅结果
     */
    private double clamp(double value, double min, double max) {
        return Math.max(min, Math.min(max, value));
    }

    /**
     * 同源基础状态。
     */
    private static final class MeasurementState {

        /** 共享种子。 */
        private final long sharedSeed;
        /** 电压有效值。 */
        private final double phaseVoltage;
        /** AB 线电压。 */
        private final double lineVoltageAB;
        /** BC 线电压。 */
        private final double lineVoltageBC;
        /** CA 线电压。 */
        private final double lineVoltageCA;
        /** 频率。 */
        private final double frequency;
        /** 频偏。 */
        private final double frequencyDeviation;
        /** 电流有效值。 */
        private final double currentRms;
        /** 电压正序。 */
        private final double vPositive;
        /** 电压负序。 */
        private final double vNegative;
        /** 电压零序。 */
        private final double vZero;
        /** 电压不平衡度。 */
        private final double vUnbalance;
        /** 电压上偏差。 */
        private final double vUpperDeviation;
        /** 电压下偏差。 */
        private final double vLowerDeviation;
        /** 电流正序。 */
        private final double iPositive;
        /** 电流负序。 */
        private final double iNegative;
        /** 电流零序。 */
        private final double iZero;
        /** 电流不平衡度。 */
        private final double iUnbalance;
        /** 电压谐波。 */
        private final double[] vHarmonics;
        /** 电流谐波。 */
        private final double[] iHarmonics;
        /** 间谐波电流。 */
        private final double[] iInharmonics;
        /** 电压 thd。 */
        private final double vThd;
        /** 电流 thd。 */
        private final double iThd;
        /** 有功谐波功率。 */
        private final double[] pHarmonics;
        /** 无功谐波功率。 */
        private final double[] qHarmonics;
        /** 视在谐波功率。 */
        private final double[] sHarmonics;
        /** 总有功。 */
        private final double activePower;
        /** 总无功。 */
        private final double reactivePower;
        /** 总视在。 */
        private final double apparentPower;
        /** 功率因数。 */
        private final double powerFactor;
        /** 畸变因数。 */
        private final double distortionFactor;
        /** 波动值。 */
        private final double fluc;
        /** 短时闪变。 */
        private final double pst;
        /** 长时闪变。 */
        private final double plt;
        /** 波动修正值。 */
        private final double flucCf;

        private MeasurementState(long sharedSeed, double phaseVoltage, double lineVoltageAB, double lineVoltageBC, double lineVoltageCA,
                                 double frequency, double frequencyDeviation, double currentRms, double vPositive, double vNegative,
                                 double vZero, double vUnbalance, double vUpperDeviation, double vLowerDeviation, double iPositive,
                                 double iNegative, double iZero, double iUnbalance, double[] vHarmonics, double[] iHarmonics,
                                 double[] iInharmonics, double vThd, double iThd, double[] pHarmonics, double[] qHarmonics,
                                 double[] sHarmonics, double activePower, double reactivePower, double apparentPower,
                                 double powerFactor, double distortionFactor, double fluc, double pst, double plt, double flucCf) {
            this.sharedSeed = sharedSeed;
            this.phaseVoltage = phaseVoltage;
            this.lineVoltageAB = lineVoltageAB;
            this.lineVoltageBC = lineVoltageBC;
            this.lineVoltageCA = lineVoltageCA;
            this.frequency = frequency;
            this.frequencyDeviation = frequencyDeviation;
            this.currentRms = currentRms;
            this.vPositive = vPositive;
            this.vNegative = vNegative;
            this.vZero = vZero;
            this.vUnbalance = vUnbalance;
            this.vUpperDeviation = vUpperDeviation;
            this.vLowerDeviation = vLowerDeviation;
            this.iPositive = iPositive;
            this.iNegative = iNegative;
            this.iZero = iZero;
            this.iUnbalance = iUnbalance;
            this.vHarmonics = vHarmonics;
            this.iHarmonics = iHarmonics;
            this.iInharmonics = iInharmonics;
            this.vThd = vThd;
            this.iThd = iThd;
            this.pHarmonics = pHarmonics;
            this.qHarmonics = qHarmonics;
            this.sHarmonics = sHarmonics;
            this.activePower = activePower;
            this.reactivePower = reactivePower;
            this.apparentPower = apparentPower;
            this.powerFactor = powerFactor;
            this.distortionFactor = distortionFactor;
            this.fluc = fluc;
            this.pst = pst;
            this.plt = plt;
            this.flucCf = flucCf;
        }
    }
}
