package com.njcn.advance.responsibility.analysis;

import com.njcn.advance.responsibility.constant.HarmonicConstants;
import com.njcn.advance.responsibility.utils.MathUtils;
import org.apache.commons.math3.linear.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 典则相关分析类
 * 实现典则相关系数的计算
 *
 * @author hongawen
 * @version 1.0
 */
public class CanonicalCorrelationAnalysis {

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

    /**
     * 计算典则相关系数
     * 对应C代码中的TransCancor函数
     *
     * @param powerData    功率数据矩阵 [时间][节点]
     * @param harmonicData 谐波数据向量
     * @param windowSize   窗口大小
     * @param nodeCount    节点数量
     * @return 典则相关系数
     */
    public static float computeCanonicalCorrelation(float[][] powerData, float[] harmonicData,
                                                    int windowSize, int nodeCount) {
        logger.info("===== 开始典型相关分析 =====");
        logger.info("输入参数: windowSize={}, nodeCount={}", windowSize, nodeCount);

        try {
            // 提取窗口数据
            double[][] x = new double[windowSize][nodeCount];
            double[] y = new double[windowSize];

            // ===== 数据质量统计（只统计，不影响计算） =====
            int nanCountPower = 0, infiniteCountPower = 0, zeroCountPower = 0;
            int nanCountHarmonic = 0, infiniteCountHarmonic = 0, zeroCountHarmonic = 0;
            double powerSum = 0, harmonicSum = 0;
            double powerMin = Double.MAX_VALUE, powerMax = -Double.MAX_VALUE;
            double harmonicMin = Double.MAX_VALUE, harmonicMax = -Double.MAX_VALUE;

            for (int i = 0; i < windowSize; i++) {
                for (int j = 0; j < nodeCount; j++) {
                    float val = powerData[i][j];
                    x[i][j] = val;

                    // 仅统计，不改变原逻辑
                    if (Float.isNaN(val)) {
                        nanCountPower++;
                    } else if (Float.isInfinite(val)) {
                        infiniteCountPower++;
                    } else if (val == 0.0f) {
                        zeroCountPower++;
                    } else {
                        powerSum += val;
                        powerMin = Math.min(powerMin, val);
                        powerMax = Math.max(powerMax, val);
                    }
                }

                float harmonicVal = harmonicData[i];
                y[i] = harmonicVal;

                // 仅统计，不改变原逻辑
                if (Float.isNaN(harmonicVal)) {
                    nanCountHarmonic++;
                } else if (Float.isInfinite(harmonicVal)) {
                    infiniteCountHarmonic++;
                } else if (harmonicVal == 0.0f) {
                    zeroCountHarmonic++;
                } else {
                    harmonicSum += harmonicVal;
                    harmonicMin = Math.min(harmonicMin, harmonicVal);
                    harmonicMax = Math.max(harmonicMax, harmonicVal);
                }
            }

            // ===== 数据质量报告（只记录日志） =====
            int totalPowerCount = windowSize * nodeCount;
            int totalHarmonicCount = windowSize;

            logger.info("功率数据质量分析:");
            logger.info("  总数据点: {}", totalPowerCount);
            logger.info("  NaN数量: {} ({:.2f}%)", nanCountPower, nanCountPower * 100.0 / totalPowerCount);
            logger.info("  无穷大数量: {} ({:.2f}%)", infiniteCountPower, infiniteCountPower * 100.0 / totalPowerCount);
            logger.info("  零值数量: {} ({:.2f}%)", zeroCountPower, zeroCountPower * 100.0 / totalPowerCount);
            logger.info("  有效数据范围: [{}, {}]", powerMin == Double.MAX_VALUE ? "N/A" : powerMin,
                    powerMax == -Double.MAX_VALUE ? "N/A" : powerMax);

            logger.info("谐波数据质量分析:");
            logger.info("  总数据点: {}", totalHarmonicCount);
            logger.info("  NaN数量: {} ({:.2f}%)", nanCountHarmonic, nanCountHarmonic * 100.0 / totalHarmonicCount);
            logger.info("  无穷大数量: {} ({:.2f}%)", infiniteCountHarmonic, infiniteCountHarmonic * 100.0 / totalHarmonicCount);
            logger.info("  零值数量: {} ({:.2f}%)", zeroCountHarmonic, zeroCountHarmonic * 100.0 / totalHarmonicCount);
            logger.info("  有效数据范围: [{}, {}]", harmonicMin == Double.MAX_VALUE ? "N/A" : harmonicMin,
                    harmonicMax == -Double.MAX_VALUE ? "N/A" : harmonicMax);

            // 只记录警告，不停止计算
            if (nanCountPower > 0 || infiniteCountPower > 0) {
                logger.warn("功率数据包含异常值！NaN: {}, Infinite: {}", nanCountPower, infiniteCountPower);
            }
            if (nanCountHarmonic > 0 || infiniteCountHarmonic > 0) {
                logger.warn("谐波数据包含异常值！NaN: {}, Infinite: {}", nanCountHarmonic, infiniteCountHarmonic);
            }

            // 计算协方差矩阵 SXX
            logger.info("===== 开始协方差计算 =====");
            double[][] sxxMatrix = MathUtils.covarianceMatrix(x, windowSize, nodeCount);

            // ===== SXX矩阵诊断（只记录日志）=====
            double sxxTrace = 0;
            double sxxFrobeniusNorm = 0;
            boolean sxxHasNaN = false, sxxHasInfinite = false;

            for (int i = 0; i < nodeCount; i++) {
                sxxTrace += sxxMatrix[i][i];
                for (int j = 0; j < nodeCount; j++) {
                    double val = sxxMatrix[i][j];
                    if (Double.isNaN(val)) {
                        sxxHasNaN = true;
                    }
                    if (Double.isInfinite(val)) {
                        sxxHasInfinite = true;
                    }
                    sxxFrobeniusNorm += val * val;
                }
            }
            sxxFrobeniusNorm = Math.sqrt(sxxFrobeniusNorm);

            logger.info("SXX矩阵诊断:");
            logger.info("  维度: {}x{}", nodeCount, nodeCount);
            logger.info("  迹(trace): {}", sxxTrace);
            logger.info("  Frobenius范数: {}", sxxFrobeniusNorm);
            logger.info("  包含NaN: {}", sxxHasNaN);
            logger.info("  包含无穷大: {}", sxxHasInfinite);
            logger.info("  对角线元素: {}", java.util.Arrays.toString(
                    java.util.stream.IntStream.range(0, nodeCount)
                            .mapToDouble(i -> sxxMatrix[i][i])
                            .toArray()));

            // 计算协方差 SYY
            double syyMatrix = MathUtils.covariance(y, y, windowSize);
            logger.info("SYY协方差: {}", syyMatrix);

            if (Math.abs(syyMatrix) < HarmonicConstants.MIN_COVARIANCE) {
                logger.warn("SYY过小 ({}), 调整为最小值: {}", syyMatrix, HarmonicConstants.MIN_COVARIANCE);
                syyMatrix = HarmonicConstants.MIN_COVARIANCE;
            }

            // 计算协方差向量 SXY
            double[] sxyVector = MathUtils.covarianceVector(x, y, windowSize, nodeCount);

            // ===== SXY向量诊断（只记录日志）=====
            double sxyNorm = 0;
            boolean sxyHasNaN = false, sxyHasInfinite = false;
            for (double val : sxyVector) {
                if (Double.isNaN(val)) {
                    sxyHasNaN = true;
                }
                if (Double.isInfinite(val)) {
                    sxyHasInfinite = true;
                }
                sxyNorm += val * val;
            }
            sxyNorm = Math.sqrt(sxyNorm);

            logger.info("SXY向量诊断:");
            logger.info("  长度: {}", sxyVector.length);
            logger.info("  L2范数: {}", sxyNorm);
            logger.info("  包含NaN: {}", sxyHasNaN);
            logger.info("  包含无穷大: {}", sxyHasInfinite);
            logger.info("  向量值: {}", java.util.Arrays.toString(sxyVector));

            // 使用Apache Commons Math进行矩阵运算
            logger.info("===== 开始矩阵分解 =====");
            RealMatrix sxx = new Array2DRowRealMatrix(sxxMatrix);
            RealVector sxy = new ArrayRealVector(sxyVector);

            // 计算 SXX^(-1)
            logger.info("准备计算SXX逆矩阵...");
            DecompositionSolver solver = new LUDecomposition(sxx).getSolver();
            RealMatrix invSxx;

            // 检查矩阵奇异性
            double sxxDet = new LUDecomposition(sxx).getDeterminant();
            logger.info("SXX矩阵行列式: {}", sxxDet);

            if (Math.abs(sxxDet) < 1e-15) {
                logger.warn("SXX矩阵几乎奇异 (det={})", sxxDet);
            }

            if (!solver.isNonSingular()) {
                // 如果矩阵奇异，使用伪逆
                logger.warn("SXX matrix is singular, using pseudo-inverse");
                try {
                    SingularValueDecomposition svd = new SingularValueDecomposition(sxx);
                    invSxx = svd.getSolver().getInverse();
                } catch (Exception svdException) {
                    logger.error("SVD pseudo-inverse failed, using regularized inverse", svdException);
                    // 添加正则化项
                    RealMatrix identity = MatrixUtils.createRealIdentityMatrix(sxx.getRowDimension());
                    RealMatrix regularized = sxx.add(identity.scalarMultiply(1e-10));
                    invSxx = new LUDecomposition(regularized).getSolver().getInverse();
                }
            } else {
                invSxx = solver.getInverse();
            }

            // 计算 U = SXX^(-1) * SXY * (1/SYY) * SXY'
            RealVector temp = invSxx.operate(sxy);
            double scale = 1.0 / syyMatrix;
            RealMatrix uMatrix = temp.outerProduct(sxy).scalarMultiply(scale);

            // 计算特征值 - 添加数值稳定性处理
            double maxEigenvalue = 0.0;

            try {
                // 首先检查矩阵是否有效
                double[][] uMatrixData = uMatrix.getData();
                boolean hasNaN = false;
                boolean hasInfinite = false;

                for (int i = 0; i < uMatrixData.length; i++) {
                    for (int j = 0; j < uMatrixData[i].length; j++) {
                        if (Double.isNaN(uMatrixData[i][j])) {
                            hasNaN = true;
                        }
                        if (Double.isInfinite(uMatrixData[i][j])) {
                            hasInfinite = true;
                        }
                    }
                }

                if (hasNaN || hasInfinite) {
                    logger.warn("U matrix contains NaN or Infinite values, returning 0");
                    return 0.0f;
                }

                // 检查矩阵条件数
                SingularValueDecomposition svdCheck = new SingularValueDecomposition(uMatrix);
                double conditionNumber = svdCheck.getConditionNumber();

                if (conditionNumber > 1e12) {
                    logger.warn("U matrix is ill-conditioned (condition number: {}), using SVD approach", conditionNumber);

                    // 使用SVD方法获取最大奇异值的平方作为最大特征值
                    double[] singularValues = svdCheck.getSingularValues();
                    if (singularValues.length > 0) {
                        maxEigenvalue = singularValues[0] * singularValues[0];
                    }
                } else {
                    // 正常的特征值分解
                    EigenDecomposition eigenDecomposition = new EigenDecomposition(uMatrix);
                    double[] eigenvalues = eigenDecomposition.getRealEigenvalues();

                    // 找最大特征值
                    for (double eigenvalue : eigenvalues) {
                        maxEigenvalue = Math.max(maxEigenvalue, Math.abs(eigenvalue));
                    }
                }

            } catch (Exception eigenException) {
                logger.warn("EigenDecomposition failed, trying alternative approach: {}", eigenException.getMessage());

                // 备用方案：使用SVD方法
                try {
                    SingularValueDecomposition svd = new SingularValueDecomposition(uMatrix);
                    double[] singularValues = svd.getSingularValues();
                    if (singularValues.length > 0) {
                        maxEigenvalue = singularValues[0] * singularValues[0];
                    }
                } catch (Exception svdException) {
                    logger.error("Both EigenDecomposition and SVD failed, returning 0", svdException);
                    return 0.0f;
                }
            }

            // 典则相关系数是最大特征值的平方根
            double canonicalCorr = Math.sqrt(Math.abs(maxEigenvalue));

            // 限制在[0,1]范围内
            if (canonicalCorr > 1.0) {
                canonicalCorr = 1.0;
            }

            logger.info("===== 典型相关分析计算完成 =====");
            logger.info("最大特征值: {}", maxEigenvalue);
            logger.info("典型相关系数: {}", canonicalCorr);
            logger.info("是否被截断到1.0: {}", canonicalCorr >= 1.0);

            return (float) canonicalCorr;

        } catch (Exception e) {
            logger.error("Error computing canonical correlation", e);
            logger.error("异常详情: {}", e.getMessage());
            logger.error("异常类型: {}", e.getClass().getSimpleName());
            return 0.0f;
        }
    }

    /**
     * 滑动窗口计算典则相关系数序列
     * 对应C代码中的SlideCanCor函数
     *
     * @param powerData    功率数据矩阵 [时间][节点]
     * @param harmonicData 谐波数据向量
     * @param windowSize   窗口大小
     * @param nodeCount    节点数量
     * @param dataLength   数据总长度
     * @return 典则相关系数序列
     */
    public static float[] slidingCanonicalCorrelation(float[][] powerData, float[] harmonicData,
                                                      int windowSize, int nodeCount, int dataLength) {
        int slideLength = dataLength - windowSize;
        if (slideLength <= 0) {
            throw new IllegalArgumentException("Data length must be greater than window size");
        }

        float[] slideCanCor = new float[slideLength];

        logger.info("Starting sliding canonical correlation analysis, slide length: {}", slideLength);

        for (int i = 0; i < slideLength; i++) {
            // 提取窗口数据
            float[][] windowPower = new float[windowSize][nodeCount];
            float[] windowHarmonic = new float[windowSize];

            for (int j = 0; j < windowSize; j++) {
                System.arraycopy(powerData[i + j], 0, windowPower[j], 0, nodeCount);
                windowHarmonic[j] = harmonicData[i + j];
            }

            // 计算当前窗口的典则相关系数
            slideCanCor[i] = computeCanonicalCorrelation(windowPower, windowHarmonic,
                    windowSize, nodeCount);

            if (i % 10 == 0) {
                logger.debug("Processed window {}/{}", i, slideLength);
            }
        }

        logger.info("Sliding canonical correlation analysis completed");

        return slideCanCor;
    }

    /**
     * 计算包含/不包含背景的动态相关系数
     * 对应C代码中的SlideCor函数
     *
     * @param powerData    功率数据（单个节点）
     * @param harmonicData 谐波数据
     * @param slideCanCor  滑动典则相关系数
     * @param windowSize   窗口大小
     * @return 动态相关系数序列
     */
    public static float[] slidingCorrelation(float[] powerData, float[] harmonicData,
                                             float[] slideCanCor, int windowSize) {
        int slideLength = slideCanCor.length;
        float[] slideCor = new float[slideLength];

        for (int i = 0; i < slideLength; i++) {
            float[] tempPower = new float[windowSize];
            float[] tempHarmonic = new float[windowSize];

            for (int j = 0; j < windowSize; j++) {
                tempPower[j] = powerData[i + j];
                tempHarmonic[j] = harmonicData[i + j] * slideCanCor[i];
            }

            slideCor[i] = MathUtils.pearsonCorrelation(tempHarmonic, tempPower, windowSize);
        }

        return slideCor;
    }
}