#include <iostream>
#include <limits>

#include "global.h"

namespace Global {
    Mode _mode = Mode::Analysis;

    AxisMode _axisMode = AxisMode::SingleY;

    QVector<CurveFileData> _curveFileDataVtr;

    int                          _currentPhase = 0;
    ExperimentInfo               _experimentInfo;
    QVector<CurveExperimentData> _curveExperimentDataVtr;
    CurveExperimentData         *_currentCurveExperimentDataPtr = nullptr;

    bool                         _smoothnessFlag = false;
    QVector<CurveExperimentData> _curveSmoothnessDataVtr;
    QString                      _smoothnessFileName;

    bool            _enthalpyCoefficientEnableFlag = false;
    QVector<double> _enthalpyCoefficientVtr;

    bool _displayTimeValue = false;

    LanguageType _languageType = LanguageType::Chinese;

    bool _experimentOITFlag = false;

    // OIT auto mode.
    bool   _OITAutoAnalysisModeFlag    = false;
    double _OITAutoAnalysisCoefficient = OITAutoAnalysisDefaultCoefficient;
    double _OITAutoAnalysisThreshold   = OITAutoAnalysisDefaultThreshold;
    // 实验文件
    QStringList _fileList;

    QString converDoubleToStr(const double num) {
        return QString::number(num, 'f', 3);
    }

    void quadraticLeastSquaresFit(double x[], double y[], int n, double coeff[]) {
        if (n < 3) {
            throw std::invalid_argument("At least 3 data points are required for quadratic fitting");
        }

        double sum_x = 0, sum_x2 = 0, sum_x3 = 0, sum_x4 = 0;
        double sum_y = 0, sum_xy = 0, sum_x2y = 0;

        // 计算各项累加和
        for (int i = 0; i < n; ++i) {
            double xi  = x[i];
            double xi2 = xi * xi;
            double xi3 = xi2 * xi;
            double xi4 = xi3 * xi;
            double yi  = y[i];

            sum_x += xi;
            sum_x2 += xi2;
            sum_x3 += xi3;
            sum_x4 += xi4;
            sum_y += yi;
            sum_xy += xi * yi;
            sum_x2y += xi2 * yi;
        }

        // 构建正规方程组的增广矩阵
        double matrix[3][4] = {
            { sum_x4, sum_x3, sum_x2, sum_x2y },                // 对应方程: a*Σx⁴ + b*Σx³ + c*Σx² = Σx²y
            { sum_x3, sum_x2, sum_x, sum_xy },                  // 对应方程: a*Σx³ + b*Σx² + c*Σx = Σxy
            { sum_x2, sum_x, static_cast<double>(n), sum_y }    // 对应方程: a*Σx² + b*Σx + c*n = Σy
        };

        // 高斯消元法解方程组
        for (int i = 0; i < 3; ++i) {
            // 部分主元选择
            int maxRow = i;
            for (int k = i + 1; k < 3; ++k) {
                if (std::abs(matrix[k][i]) > std::abs(matrix[maxRow][i])) {
                    maxRow = k;
                }
            }

            // 交换行
            for (int k = i; k < 4; ++k) {
                std::swap(matrix[i][k], matrix[maxRow][k]);
            }

            // 消元
            for (int k = i + 1; k < 3; ++k) {
                double factor = matrix[k][i] / matrix[i][i];
                for (int j = i; j < 4; ++j) {
                    matrix[k][j] -= factor * matrix[i][j];
                }
            }
        }

        // 回代求解
        coeff[2] = matrix[2][3] / matrix[2][2];                                                          // c
        coeff[1] = (matrix[1][3] - matrix[1][2] * coeff[2]) / matrix[1][1];                              // b
        coeff[0] = (matrix[0][3] - matrix[0][2] * coeff[2] - matrix[0][1] * coeff[1]) / matrix[0][0];    // a
    }

    // 计算一元一次函数在给定区间内开始变成负值的点
    double findNegativeStartPoint(double m, double b, double start, double end) {
        // 处理斜率为零的情况
        if (m == 0) {
            // 当斜率为 0 时，函数值为常数 b
            if (b < 0) {
                return start;    // 若 b 为负，函数在区间起始点就为负
            } else {
                return std::numeric_limits<double>::infinity();    // 若 b 非负，函数在区间内不会变负
            }
        }

        // 计算零点
        double zeroPoint = -b / m;

        // 检查零点是否在给定区间内
        if (zeroPoint >= start && zeroPoint <= end) {
            return zeroPoint;    // 零点在区间内，函数在此点开始变负
        }

        // 根据斜率正负判断函数单调性，进而判断函数在区间内是否会变负
        if (m > 0) {
            // 斜率大于 0，函数单调递增
            if (m * start + b < 0) {
                return start;    // 起始点函数值为负，函数在起始点就为负
            }
        } else {
            // 斜率小于 0，函数单调递减
            if (m * end + b < 0) {
                return end;    // 结束点函数值为负，函数在结束点开始为负
            }
        }

        // 函数在区间内不会变负
        return std::numeric_limits<double>::infinity();
    }

    void clearExperimentData() {
        _curveExperimentDataVtr.clear();
        _currentCurveExperimentDataPtr = nullptr;
        _currentPhase                  = -1;
    }

    bool isZero(double value, double epsilon) {
        return std::abs(value) < epsilon;
    }

    bool isEqual(const double a, const double b) {
        const double tolerance = 1e-5;    // 容差值，可以根据需要调整
        return std::fabs(a - b) < tolerance;
    }

    QString getFileName(const QString filePath) {
        QFileInfo fileInfo(filePath);

        // 获取文件的后缀名并转换为小写，方便比较
        QString fileSuffix = fileInfo.suffix().toLower();

        return fileInfo.fileName();
    }

    double converStrToDouble(const QString str) {
        bool   ok;
        double value = str.toDouble(&ok);    // 将字符串转换为 double，并检查是否成功
        if (!ok) {
            qDebug() << "转换失败，输入的字符串不是有效的数字";
            return 0.0;    // 如果转换失败，返回默认值
        }
        return value;
    }
    bool isFileExist(const QString &fileName) {
        return _fileList.contains(fileName);
    }

    
void updateFileList()
{
    _fileList.clear();

    QDir dir(SampleDataFloder);
    _fileList.append(dir.entryList(QDir::Files));
#if 0
    dir.setPath(BaseLineFolder);
    _fileList.append(dir.entryList(QDir::Files));
#endif
    dir.setPath(AnalysisStateFolder);
    _fileList.append(dir.entryList(QDir::Files));
}

}    // namespace Global

#if 0
Global::Global()
{
    _mode = Global::Mode::Analysis;
    _deviceConnectStatus = Global::DeviceConnectionStatus::Disconnected;
}

Global *Global::instance()
{
    static Global ins;
    return &ins;
}

void Global::setMode(const Global::Mode mode)
{
    if(mode != _mode){
        _mode = mode;
        emit sigModeModify(mode);
    }
}

#if 0
void Global::setDeviceConnectionStatus(const Global::DeviceConnectionStatus status)
{
    if(status != _deviceConnectStatus){
        _deviceConnectStatus = status;
        emit sigDeviceConnnectionStatusModify(status);
    }
}
#endif

#endif
