package com.njcn.product.advance.responsility.calculator;

import com.njcn.product.advance.responsility.analysis.CanonicalCorrelationAnalysis;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 责任指标计算类
 * 计算谐波责任的各项指标
 * 严格对应C代码实现
 *
 * @author hongawen
 * @version 2.0 - 修复版本，严格对照C代码实现
 */
public class ResponsibilityCalculator {

    private static final Logger logger = LoggerFactory.getLogger(ResponsibilityCalculator.class);

    /**
     * 计算EK值（动态责任指标）
     * 严格对应C代码中的DyEKCom函数（行300-357）
     *
     * @param correlationData 动态相关系数矩阵 [时间][节点]
     * @param powerData 功率数据矩阵 [时间][节点]
     * @param windowSize 窗口大小
     * @param nodeCount 节点数量
     * @param dataLength 数据长度
     * @return EK值矩阵
     */
    public static float[][] computeEK(float[][] correlationData, float[][] powerData,
                                      int windowSize, int nodeCount, int dataLength) {
        int slideLength = dataLength - windowSize;
        float[][] ekData = new float[slideLength][nodeCount];
        float[][] akData = new float[slideLength][nodeCount];

        logger.info("Computing EK values, slide length: {}", slideLength);

        // 计算AK值 - 对应C代码行307-319
        for (int i = 0; i < slideLength; i++) {
            float sumPower = 0;

            // 计算功率总和 - 对应C代码行309-313
            for (int j = 0; j < nodeCount; j++) {
                sumPower += powerData[i][j];  // 注意：这里用的是powerData[i][j]
            }

            // 计算AK值 - 对应C代码行314-318
            for (int j = 0; j < nodeCount; j++) {
                if (sumPower > 0) {
                    akData[i][j] = correlationData[i][j] * (powerData[i][j] / sumPower);
                } else {
                    akData[i][j] = 0;
                }
            }
        }

        // 归一化处理得到EK值 - 对应C代码行320-342
        for (int i = 0; i < slideLength; i++) {
            // 重要：C代码初始化为0，而不是Float.MIN_VALUE/MAX_VALUE
            // 对应C代码行322-323
            float maxValue = 0;
            float minValue = 0;

            // 找最大最小值 - 对应C代码行322-334
            for (int j = 0; j < nodeCount; j++) {
                if (akData[i][j] > maxValue) {
                    maxValue = akData[i][j];
                }
                if (akData[i][j] < minValue) {
                    minValue = akData[i][j];
                }
            }

            float range = maxValue - minValue;

            // 归一化 - 对应C代码行338-341
            for (int j = 0; j < nodeCount; j++) {
                if (Math.abs(range) > 1e-10) {
                    ekData[i][j] = (akData[i][j] - minValue) / range;
                } else {
                    ekData[i][j] = 0;
                }
            }
        }

        logger.info("EK computation completed");

        return ekData;
    }

    /**
     * 计算FK值（不包含背景的责任指标）
     * 严格对应C代码中的DyFKCom函数（行358-389）
     *
     * @param ekData EK值矩阵
     * @param windowSize 窗口大小
     * @param nodeCount 节点数量
     * @param dataLength 数据长度
     * @return FK值矩阵
     */
    public static float[][] computeFK(float[][] ekData, int windowSize,
                                      int nodeCount, int dataLength) {
        int slideLength = dataLength - windowSize;
        float[][] fkData = new float[slideLength][nodeCount];

        logger.info("Computing FK values");

        // 对应C代码行364-376
        for (int i = 0; i < slideLength; i++) {
            float sumEK = 0;

            // 计算EK总和 - 对应C代码行366-370
            for (int j = 0; j < nodeCount; j++) {
                sumEK += ekData[i][j];
            }

            // 计算FK值（归一化）- 对应C代码行372-375
            for (int j = 0; j < nodeCount; j++) {
                if (sumEK > 0) {
                    fkData[i][j] = ekData[i][j] / sumEK;
                } else {
                    fkData[i][j] = 0;
                }
            }
        }

        logger.info("FK computation completed");

        return fkData;
    }

    /**
     * 计算HK值（包含背景的责任指标）
     * 严格对应C代码中的DyHKCom函数（行390-429）
     *
     * @param backgroundCanCor 背景典则相关系数（1-典则相关系数）
     * @param ekData EK值矩阵
     * @param windowSize 窗口大小
     * @param nodeCount 节点数量
     * @param dataLength 数据长度
     * @return HK值矩阵
     */
    public static float[][] computeHK(float[] backgroundCanCor, float[][] ekData,
                                      int windowSize, int nodeCount, int dataLength) {
        int slideLength = dataLength - windowSize;
        float[][] hkData = new float[slideLength][nodeCount + 1];
        float[][] newEK = new float[slideLength][nodeCount + 1];

        logger.info("Computing HK values");

        // 构建包含背景的EK矩阵 - 对应C代码行396-403
        for (int i = 0; i < slideLength; i++) {
            // 复制原有EK值
            for (int j = 0; j < nodeCount; j++) {
                newEK[i][j] = ekData[i][j];
            }
            // 添加背景值
            newEK[i][nodeCount] = backgroundCanCor[i];
        }

        // 计算HK值 - 对应C代码行405-416
        for (int i = 0; i < slideLength; i++) {
            float sumEK = 0;

            // 计算总和 - 对应C代码行407-411
            for (int j = 0; j < nodeCount + 1; j++) {
                sumEK += newEK[i][j];
            }

            // 归一化得到HK值 - 对应C代码行412-415
            for (int j = 0; j < nodeCount + 1; j++) {
                if (sumEK > 0) {
                    hkData[i][j] = newEK[i][j] / sumEK;
                } else {
                    hkData[i][j] = 0;
                }
            }
        }

        logger.info("HK computation completed");

        return hkData;
    }

    /**
     * 计算超限时段的责任总和
     * 严格对应C代码中的SumHK函数（行431-461）
     *
     * @param responsibilityData 责任数据矩阵（FK或HK）[时间][节点]
     * @param harmonicData 谐波数据（Udata） - 长度为TL
     * @param threshold 谐波门槛（XIANE）
     * @param windowSize 窗口大小
     * @param columnCount 列数（节点数或节点数+1）
     * @param tl_num 对应C代码的TL参数（总数据点数）
     * @return 各节点的责任总和百分比
     */
    public static float[] sumResponsibility(float[][] responsibilityData, float[] harmonicData,
                                            float threshold, int windowSize, int columnCount, int tl_num) {
        // 对应C代码：int slg = tl_num - width;
        int slideLength = tl_num - windowSize;  // 使用传入的tl_num计算，而不是从responsibilityData.length推断
        float[] sumData = new float[columnCount];    // 对应C代码中的 arrHKsum
        double[] HKSum = new double[columnCount];     // 对应C代码中的 VectorXd HKSum - 使用double精度
        int exceedCount = 0;                          // 对应C代码中的 coutt

        // ===== 添加详细调试日志 =====
        logger.info("======= 开始 sumResponsibility 计算 =======");
        logger.info("输入参数:");
        logger.info("  threshold(阈值): {}", threshold);
        logger.info("  windowSize(窗口大小): {}", windowSize);
        logger.info("  columnCount(列数): {}", columnCount);
        logger.info("  tl_num(总数据长度): {}", tl_num);
        logger.info("  slideLength(滑动长度): {}", slideLength);
        logger.info("  responsibilityData维度: {}x{}",
                responsibilityData != null ? responsibilityData.length : "null",
                responsibilityData != null && responsibilityData.length > 0 ? responsibilityData[0].length : "null");
        logger.info("  harmonicData长度: {}", harmonicData != null ? harmonicData.length : "null");

        // 数据验证
        if (harmonicData == null) {
            logger.error("错误: harmonicData为null!");
            throw new NullPointerException("harmonicData不能为null");
        }

        if (responsibilityData == null) {
            logger.error("错误: responsibilityData为null!");
            throw new NullPointerException("responsibilityData不能为null");
        }


        // 关键验证：检查数组长度是否充足
        // C代码中Udata长度是TL，循环遍历slg=TL-width个元素
        logger.info("数据验证: slideLength={}, harmonicData.length={}, responsibilityData.length={}",
                slideLength, harmonicData.length, responsibilityData.length);

        if (harmonicData.length < slideLength) {
            logger.error("!!!谐波数据长度不足!!!");
            logger.error("需要访问harmonicData[0]到harmonicData[{}], 但数组长度只有{}",
                    slideLength - 1, harmonicData.length);
            throw new IllegalArgumentException(
                    String.format("谐波数据长度不足: 需要%d, 实际%d", slideLength, harmonicData.length));
        }

        if (responsibilityData.length < slideLength) {
            logger.error("!!!责任数据行数不足!!!");
            logger.error("需要访问responsibilityData[0]到responsibilityData[{}], 但数组长度只有{}",
                    slideLength - 1, responsibilityData.length);
            throw new IllegalArgumentException(
                    String.format("责任数据行数不足: 需要%d, 实际%d", slideLength, responsibilityData.length));
        }

        // ===== 添加数据分布统计 =====
        logger.info("谐波数据分析:");
        float harmonicMin = Float.MAX_VALUE, harmonicMax = Float.MIN_VALUE;
        double harmonicSum = 0;
        int preliminaryExceedCount = 0;
        for (int i = 0; i < Math.min(slideLength, harmonicData.length); i++) {
            float val = harmonicData[i];
            harmonicMin = Math.min(harmonicMin, val);
            harmonicMax = Math.max(harmonicMax, val);
            harmonicSum += val;
            if (val > threshold) {
                preliminaryExceedCount++;
            }
        }
        double harmonicAvg = harmonicSum / Math.min(slideLength, harmonicData.length);
        logger.info("  谐波数据范围: [{}, {}]", harmonicMin, harmonicMax);
        logger.info("  谐波数据平均值: {}", harmonicAvg);
        logger.info("  设定阈值: {}", threshold);
        logger.info("  初步统计超限个数: {}/{} ({:.2f}%)",
                preliminaryExceedCount, Math.min(slideLength, harmonicData.length),
                preliminaryExceedCount * 100.0 / Math.min(slideLength, harmonicData.length));

        // ===== 责任数据分析 =====
        logger.info("责任数据分析(检查前5行的归一化情况):");
        for (int i = 0; i < Math.min(5, responsibilityData.length); i++) {
            float rowSum = 0;
            for (int j = 0; j < responsibilityData[i].length; j++) {
                rowSum += responsibilityData[i][j];
            }
            logger.info("  第{}行和: {} (期望值: 1.0, 偏差: {})", i, rowSum, Math.abs(rowSum - 1.0f));
        }

        // 统计超限时段的责任 - 对应C代码行437-449
        // 重要：C代码中有一个设计缺陷：coutt在每个j循环中被重置，
        // 但最后计算百分比时使用的是最后一次j循环的coutt值
        // 为了严格保持一致，我们也要复现这个逻辑
        logger.info("===== 开始循环计算每列的累加值 =====");
        int[] exceedCountPerColumn = new int[columnCount]; // 记录每列的超限次数，用于调试

        for (int j = 0; j < columnCount; j++) {
            HKSum[j] = 0;
            exceedCount = 0;  // 对应C代码行440: coutt = 0;
            logger.info("开始计算第{}列 (共{}列)", j, columnCount);

            double columnSum = 0; // 用于调试
            int columnExceedCount = 0; // 用于调试

            for (int i = 0; i < slideLength; i++) {
                // 添加越界检查
                if (i >= harmonicData.length) {
                    logger.error("!!!数组越界!!! 尝试访问harmonicData[{}], 但数组长度只有{}",
                            i, harmonicData.length);
                    logger.error("发生在: j={}, i={}", j, i);
                    throw new ArrayIndexOutOfBoundsException(
                            String.format("访问harmonicData[%d]越界, 数组长度=%d", i, harmonicData.length));
                }

                // 对应C代码行443-447
                if (harmonicData[i] > threshold) {
                    double currentResponsibility = responsibilityData[i][j];
                    HKSum[j] += currentResponsibility;  // 对应C代码行445
                    exceedCount++;  // 对应C代码行446
                    columnSum += currentResponsibility;
                    columnExceedCount++;

                    // 只打印前几个超限情况的详细信息
                    if (columnExceedCount <= 3) {
                        logger.info("  时刻i={}: 谐波值={} > 阈值={}, 责任值={}, 累加到{}",
                                i, harmonicData[i], threshold, currentResponsibility, HKSum[j]);
                    }
                }
            }

            exceedCountPerColumn[j] = columnExceedCount;
            logger.info("第{}列计算完成: 累加值={}, 超限次数={}", j, HKSum[j], columnExceedCount);
        }
        // 注意：这里exceedCount保留的是最后一列（j=columnCount-1）的超限次数
        // 这与C代码的行为一致

        logger.info("===== 循环计算完成 =====");
        logger.info("最终exceedCount={} (来自最后一列的计算)", exceedCount);
        logger.info("各列超限次数对比: {}", java.util.Arrays.toString(exceedCountPerColumn));
        logger.info("各列累加值: {}", java.util.Arrays.toString(HKSum));

        // 计算平均责任百分比 - 对应C代码行453-459
        logger.info("===== 开始计算最终百分比 =====");
        for (int i = 0; i < columnCount; i++) {
            sumData[i] = 0;  // 对应C代码行454
        }

        double totalPercentage = 0; // 用于统计总和
        for (int i = 0; i < columnCount; i++) {
            if (exceedCount > 0) {
                // 对应C代码行458: arrHKsum[i] = 100 * (HKSum(i)/coutt);
                // 使用double进行计算，然后转换为float
                double percentage = 100.0 * (HKSum[i] / (double)exceedCount);
                sumData[i] = (float)percentage;
                totalPercentage += percentage;

                logger.info("节点{}: 累加值={}, 除以超限次数={}, 百分比={}%",
                        i, HKSum[i], exceedCount, percentage);
            } else {
                logger.warn("节点{}: 超限次数为0，百分比设为0", i);
            }
        }

        logger.info("===== 计算结果汇总 =====");
        logger.info("使用的超限次数(分母): {}", exceedCount);
        logger.info("各节点百分比: {}", java.util.Arrays.toString(sumData));
        logger.info("百分比总和: {}% (期望100%)", totalPercentage);
        logger.info("偏差: {}%", Math.abs(totalPercentage - 100.0));

        if (Math.abs(totalPercentage - 100.0) > 1.0) {
            logger.warn("!!!注意!!! 百分比总和偏离100%超过1%，可能存在问题");
        }

        logger.info("======= sumResponsibility 计算完成 =======");
        return sumData;
    }

    /**
     * 计算超限时段的责任总和（兼容版本）
     * 为了向后兼容，保留不带tl_num参数的版本
     *
     * @param responsibilityData 责任数据矩阵（FK或HK）[时间][节点]
     * @param harmonicData 谐波数据（Udata）
     * @param threshold 谐波门槛（XIANE）
     * @param windowSize 窗口大小
     * @param columnCount 列数（节点数或节点数+1）
     * @return 各节点的责任总和百分比
     */
    public static float[] sumResponsibility(float[][] responsibilityData, float[] harmonicData,
                                            float threshold, int windowSize, int columnCount) {
        // 如果没有提供tl_num，从数据推断
        int tl_num = responsibilityData.length + windowSize;
        return sumResponsibility(responsibilityData, harmonicData, threshold, windowSize, columnCount, tl_num);
    }

    /**
     * 计算所有节点的动态相关系数矩阵
     * 这个函数在主引擎中已经内联实现，这里保留作为辅助方法
     *
     * @param powerData 功率数据矩阵
     * @param harmonicData 谐波数据
     * @param canonicalCorr 典则相关系数序列
     * @param windowSize 窗口大小
     * @param nodeCount 节点数量
     * @return 动态相关系数矩阵
     */
    public static float[][] computeCorrelationMatrix(float[][] powerData, float[] harmonicData,
                                                     float[] canonicalCorr, int windowSize,
                                                     int nodeCount) {
        int slideLength = canonicalCorr.length;
        float[][] correlationMatrix = new float[slideLength][nodeCount];

        logger.info("Computing correlation matrix for all nodes");

        for (int nodeIdx = 0; nodeIdx < nodeCount; nodeIdx++) {
            // 提取单个节点的功率数据
            float[] nodePower = new float[powerData.length];
            for (int i = 0; i < powerData.length; i++) {
                nodePower[i] = powerData[i][nodeIdx];
            }

            // 计算该节点的动态相关系数
            float[] nodeCorr = CanonicalCorrelationAnalysis
                    .slidingCorrelation(nodePower, harmonicData, canonicalCorr, windowSize);

            // 存储结果
            for (int i = 0; i < slideLength; i++) {
                correlationMatrix[i][nodeIdx] = nodeCorr[i];
            }
        }

        logger.info("Correlation matrix computation completed");

        return correlationMatrix;
    }
}