#include <QDebug>

#include "pointcalculate.h"
#include "logger.h"
#include "global.h"
#include "confighandler.h"
#include "oitautoanalysis.h"

QVector<Global::ExperimentData>PointCalculate:: _dataVtr;
QPointF PointCalculate::_peakPoint;
QPointF PointCalculate::_leftSelectedPoint,PointCalculate::_rightSelectedPoint;

void PointCalculate::setAnalysisData(const QVector<Global::ExperimentData> &dataVtr)
{
    _dataVtr = dataVtr;

    if(_dataVtr.empty())    {
        return;
    }

    Global::ExperimentData startPoint = _dataVtr.at(0);
    Global::ExperimentData endPoint = _dataVtr.at(_dataVtr.size() - 1);

    _leftSelectedPoint = QPointF(startPoint.sampleTemp,startPoint.dsc);
    _rightSelectedPoint = QPointF(endPoint.sampleTemp,endPoint.dsc);
}

std::vector<float> PointCalculate::movingAverage(const std::vector<float>& data, int windowSize) {
    std::vector<float> smoothedData;
    for (size_t i = 0; i < data.size(); ++i) {
        if (i + windowSize <= data.size()) {
            float sum = std::accumulate(data.begin() + i, data.begin() + i + windowSize, 0.0);
            smoothedData.push_back(sum / windowSize);
        }
    }
    return smoothedData;
}

QPointF PointCalculate::getPeakPoint(){
    int n = _dataVtr.size();

    if (n < 3) {
        return QPointF(); // 至少需要三个点才能找到波峰
    }

    QPointF uniquePeak;
    float maxDiff = -std::numeric_limits<float>::infinity();

    for (int i = 0; i < n; ++i) {
        const float currentX = _dataVtr.at(i).sampleTemp;
        const float currentY = _dataVtr.at(i).dsc;

        if (currentX < _leftSelectedPoint.x()) {
            continue;
        }
        if (currentX > _rightSelectedPoint.x()) {
            break;
        }

        // 计算当前点与左选择点 y 值的差值
        float diffLeft = std::abs(currentY - _leftSelectedPoint.y());
        // 计算当前点与右选择点 y 值的差值
        float diffRight = std::abs(currentY - _rightSelectedPoint.y());
        // 取两个差值中的较大值
        float currentDiff = std::max(diffLeft, diffRight);

        if (currentDiff > maxDiff) {
            maxDiff = currentDiff;
            uniquePeak = QPointF(currentX, currentY);
        }
    }

    _peakPoint = uniquePeak;

    //    logde<<"peakPoint:"<<_peakPoint.x()<<","<<_peakPoint.y();

    return uniquePeak;
}

QPair<QPointF, QPointF> PointCalculate::calculateMaxDiffPointDetail(
        const PointCalculate::MaxDiffPointDetailType type)
{
#if 1
    float maxDiff = std::numeric_limits<float>::min();
    QPointF currentPoint,lastPoint;

    for (int i = 0; i < _dataVtr.size() - 1; ++i) {
        const float currentX = _dataVtr.at(i).sampleTemp;
        const float currentY = _dataVtr.at(i).dsc;

        if(type == MaxDiffPointDetailType::Left){
            if(currentX <= _leftSelectedPoint.x()){
                continue;
            }
            if(currentX >= _peakPoint.x()){
                break;
            }
        }else{
            if(currentX <= _peakPoint.x()){
                continue;
            }
            if(currentX >= _rightSelectedPoint.x()){
                break;
            }
        }
        //
        const float lastX = _dataVtr.at(i + 1).sampleTemp;
        const float lastY = _dataVtr.at(i + 1).dsc;
        float diff = std::abs(currentY - lastY);
        if(diff > maxDiff){
            maxDiff = diff;

            currentPoint.setX(currentX);
            currentPoint.setY(currentY);
            lastPoint.setX(lastX);
            lastPoint.setY(lastY);
        }
    }
#endif

    return qMakePair(currentPoint,lastPoint);
}


QPair<QPointF, QPointF> PointCalculate::calculateMaxDiffPointLeft()
{
    return calculateMaxDiffPointDetail(MaxDiffPointDetailType::Left);
}

QPair<QPointF, QPointF> PointCalculate::calculateMaxDiffPointRight()
{
    return calculateMaxDiffPointDetail(MaxDiffPointDetailType::Right);
}

#if 0
QPointF PointCalculate::findClosestY(float targetX)
{
    float minDiff = std::numeric_limits<float>::max();
    QPointF resultPointF;

    for(FileManager::ExperimentData &ed:_dataVtr){
        float diff = std::abs(ed.sampleTemp - targetX);
        if (diff < minDiff) {
            minDiff = diff;
            resultPointF = QPointF(ed.sampleTemp,ed.dsc);
        }
    }

    return resultPointF;
}
#endif

#if 0
QPointF PointCalculate::findClosestPointByX(float x) {
    int left = 0;
    int right = _dataVtr.size() - 1;

    QPointF targetPoint;
    targetPoint.setX(_dataVtr.value(0).sampleTemp);
    targetPoint.setY(_dataVtr.value(0).dsc);

    while (left <= right) {
        int mid = left + (right - left) / 2;
        FileManager::ExperimentData& ed = _dataVtr[mid];

        if (std::abs(ed.sampleTemp - x) < std::abs(targetPoint.x() - x)) {
            targetPoint.setX(ed.sampleTemp);
            targetPoint.setY(ed.dsc);
        }

        if(ed.sampleTemp < x){
            left = mid + 1;
        } else {
            right = mid - 1;
        }
    }

    return targetPoint;
}
#endif

void PointCalculate::setRegionPointX(const float left, const float right)
{
    //    logde<<"dataVtr size:"<<_dataVtr.size();
    //    logde<<"select point param left,right:"<<left<<","<<right;

    _leftSelectedPoint = getClosestPointByX(left);
    _rightSelectedPoint = getClosestPointByX(right);

    _peakPoint = getPeakPoint();

    //    logde<<"peak point:"<<_peakPoint.x()<<","<<_peakPoint.y();

    //根据峰谷重置选择点。
    updateStartEndPoint();

    //    logde<<"select point left:"<<_leftSelectedPoint.x()<<","<<_leftSelectedPoint.y();
    //    logde<<"select point right:"<<_rightSelectedPoint.x()<<","<<_rightSelectedPoint.y();
}

QVector<QPointF> PointCalculate::getPeakPointGroup()
{
    QVector<QPointF> pointVtr;
    for(Global::ExperimentData& ed:_dataVtr)   {
        if(ed.sampleTemp >= _leftSelectedPoint.x() &&
                ed.sampleTemp <= _rightSelectedPoint.x()){
            pointVtr.push_back(QPointF(ed.sampleTemp,ed.dsc));
        }
    }

    return pointVtr;
}

float PointCalculate::calculateArea(const double x1,const double x2) {
    //getPoint group
    QVector<QPointF> points = getPeakPointGroup();
#if 1
    if(_axisMode == AxisMode::DoubleY){
        points = getPeakPointGroupByTime(x1,x2);
    }
#endif
    logde<<"points size:"<<points.size();

    //calculate Area
    float integral = 0.0;
    size_t n = points.size();

    if (n < 2) {
        return integral; // 至少需要两个点才能计算积分
    }

    //find a line.
    QPointF leftSelectedPoint = _leftSelectedPoint;
    QPointF rightSelectedPoint = _rightSelectedPoint;

    if(_axisMode == AxisMode::DoubleY){
        ExperimentData leftEd = getClosestDataByTime(_leftSelectedPoint.x());
        ExperimentData rightEd = getClosestDataByTime(_rightSelectedPoint.x());

        leftSelectedPoint = QPointF(leftEd.sampleTemp,leftEd.dsc);
        rightSelectedPoint = QPointF(rightEd.sampleTemp,rightEd.dsc);
    }

    float k = (leftSelectedPoint.y() - rightSelectedPoint.y()) /
            (leftSelectedPoint.x() - rightSelectedPoint.x());
    float b = leftSelectedPoint.y() - k * leftSelectedPoint.x();

    for (size_t i = 0; i < n - 1; ++i) {
#if 1
        float x1 = points[i].x();
        float y1 = points[i].y();

        float x2 = points[i + 1].x();
        float y2 = points[i + 1].y();
#endif
        float yLine1 = k * x1 + b;
        float yLine2  = k * x2 + b;

        float diff1 = y1 - yLine1;
        float diff2 = y2 - yLine2;

        float dx = x2 - x1;

        float cellArea = (diff1 + diff2) * dx /2.0;

        integral += std::abs(cellArea);
    }

    /*
     * H = K * S / w;
     */
    float coefficient = ConfigHandler::_configMap.value(ConfigHandler::ConInstrumentCoefficientStr).toFloat();
    logde<<"coefficient 1:"<<coefficient;

    if(Global::_enthalpyCoefficientEnableFlag){
        logde<<"_enthalpyCoefficientEnableFlag...";

        float startTemp = _leftSelectedPoint.x();

        float a = Global::_enthalpyCoefficientVtr.at(0);
        float b = Global::_enthalpyCoefficientVtr.at(1);
        float c = Global::_enthalpyCoefficientVtr.at(2);

        logde<<"a,b,c:"<<a<<","<<b<<","<<c;

        coefficient = a * startTemp * startTemp +
                b * startTemp +
                c;

        if(coefficient <= 0.0){
            coefficient = 1.0;
        }

        logde<<"coefficient 2:"<<coefficient;
    }

    logde<<"integral:"<<integral;
    logde<<"coefficient 3:"<<coefficient;
    logde<<"Global::DefaultParamter:"<<Global::DefaultParamter;

    float area = integral * coefficient * Global::DefaultParamter;

    logde<<"area:"<<area;

    return area;
}

QPair<QPointF, QPointF> PointCalculate::calculateStartAndEndPoint()
{
    QPair<QPointF,QPointF> leftMaxDiffPointPair =
            PointCalculate::calculateMaxDiffPointLeft();
    QPair<QPointF,QPointF> rightMaxDiffPointPair =
            PointCalculate::calculateMaxDiffPointRight();

#if 0
    logde<<"b1:"<<leftMaxDiffPointPair.first.x()<<","<<leftMaxDiffPointPair.first.y();
    logde<<"b2:"<<leftMaxDiffPointPair.second.x()<<","<<leftMaxDiffPointPair.second.y();

    logde<<"b3:"<<rightMaxDiffPointPair.first.x()<<","<<rightMaxDiffPointPair.first.y();
    logde<<"b4:"<<rightMaxDiffPointPair.second.x()<<","<<rightMaxDiffPointPair.second.y();
#endif

    QPointF startPoint = calculateIntersection(_leftSelectedPoint,_rightSelectedPoint,
                                               leftMaxDiffPointPair.first,
                                               leftMaxDiffPointPair.second);

    QPointF endPoint = calculateIntersection(_leftSelectedPoint,_rightSelectedPoint,
                                             rightMaxDiffPointPair.first,
                                             rightMaxDiffPointPair.second);

    return qMakePair(startPoint,endPoint);
}

void PointCalculate::updateStartEndPoint()
{
    //需要在a1和a2之间查询是否有高于a1和a2之间的点，若存在，则重新给a1、a2赋值
    for(Global::ExperimentData& ed:_dataVtr){
        if(ed.sampleTemp > _leftSelectedPoint.x() && ed.sampleTemp < _peakPoint.x()){
            if(_leftSelectedPoint.y() < _peakPoint.y()){
                if(ed.dsc < _leftSelectedPoint.y()){
                    _leftSelectedPoint.setX(ed.sampleTemp);
                    _leftSelectedPoint.setY(ed.dsc);
                }
            }else{
                if(ed.dsc > _leftSelectedPoint.y()){
                    _leftSelectedPoint.setX(ed.sampleTemp);
                    _leftSelectedPoint.setY(ed.dsc);
                }
            }
        }

        if(ed.sampleTemp < _rightSelectedPoint.x() && ed.sampleTemp > _peakPoint.x()){
            if(_leftSelectedPoint.y() < _peakPoint.y()){
                if(ed.dsc < _rightSelectedPoint.y()){
                    _rightSelectedPoint.setX(ed.sampleTemp);
                    _rightSelectedPoint.setY(ed.dsc);
                }
            }else{
                if(ed.dsc > _rightSelectedPoint.y()){
                    _rightSelectedPoint.setX(ed.sampleTemp);
                    _rightSelectedPoint.setY(ed.dsc);
                }
            }
        }
    }
}

QString PointCalculate::textFormatPeakPoint(const float enthalpyValue,
                                            const float peakValue,
                                            const float startPoint,
                                            const float endPoint)
{
    return QString("峰的综合信息：\n"
                   "焓值：%1 J/g \n"
                   "峰值：%2℃ \n"
                   "起始点：%3℃ \n"
                   "终止点：%4℃"
                   ).arg(QString::number(enthalpyValue, 'f', 3))
            .arg(QString::number(peakValue, 'f', 3))
            .arg(QString::number(startPoint, 'f', 3))
            .arg(QString::number(endPoint, 'f', 3));
}

// 计算两条直线的交点
QPointF PointCalculate::calculateIntersection(const QPointF p1,const QPointF p2,
                                              const QPointF p3, const QPointF p4){
    // 直线的一般式: A1x + B1y + C1 = 0 和 A2x + B2y + C2 = 0
    float A1 = p2.y() - p1.y();
    float B1 = p1.x() - p2.x();
    float C1 = A1 * p1.x() + B1 * p1.y();

    float A2 = p4.y() - p3.y();
    float B2 = p3.x() - p4.x();
    float C2 = A2 * p3.x() + B2 * p3.y();

    float determinant = A1 * B2 - A2 * B1;

    if (determinant == 0) {
        // 两条直线平行或重合，无交点或无限交点
        return {0, 0};
    } else {
        float x = (B2 * C1 - B1 * C2) / determinant;
        float y = (A1 * C2 - A2 * C1) / determinant;
        return {x, y};
    }
}

QPair<float,float> PointCalculate::getCurveInflectionPointTangent(const float x1,const float x2)
{
    std::vector<float> dataVtr;
    for(Global::ExperimentData& ed:_dataVtr){
        if(x1 < ed.sampleTemp && ed.sampleTemp < x2){
            dataVtr.push_back(ed.sampleTemp);
        }
    }
    // 5
    std::vector<float> processedVtr = movingAverage(dataVtr,5);

    // find max slope.
    float maxSlope = 0.0;
    float targetX = 0.0;
    for (size_t i = 1; i < processedVtr.size(); ++i) {
        float slope = processedVtr[i] - processedVtr[i - 1];
        if(std::abs(slope) > maxSlope){
            maxSlope = slope;
            targetX = processedVtr[i];
        }
    }

    // calculate line slope and axis Y space number b.
    QPointF point = getClosestPointByX(targetX);

    // 使用点斜式方程求y轴截距
    // y = m * x + b
    //      double b = y - m * x;
    float b = point.y() - maxSlope * point.x();

    return qMakePair<float,float>(maxSlope,b);
}

QPointF PointCalculate::getIntersection(const Line& line1, const Line& line2) {
    float x = (line2.intercept - line1.intercept) / (line1.slope - line2.slope);
    float y = line1.slope * x + line1.intercept;
    //    return {x, y};
    return QPointF(x,y);
}

#if 1
QPointF PointCalculate::getClosestPointByX(const float targetX)
{
    QPointF resultPointF;

    if(targetX < _dataVtr.first().sampleTemp ||
            targetX > _dataVtr.last().sampleTemp){
        return resultPointF;
    }

    float minDiff = std::numeric_limits<float>::max();

    for(Global::ExperimentData &ed:_dataVtr){
        float diff = std::abs(ed.sampleTemp - targetX);
        if (diff < minDiff) {
            minDiff = diff;
            resultPointF = QPointF(ed.sampleTemp,ed.dsc);
        }
    }

    return resultPointF;
}
#endif

Global::ExperimentData PointCalculate::getClosestDataByTemperature(const float temp)
{
    ExperimentData resultData;

#if 0
    if(temp < _dataVtr.first().sampleTemp ||
            temp > _dataVtr.last().sampleTemp){
        return resultData;
    }
#endif

    float minDiff = std::numeric_limits<float>::max();

    for(Global::ExperimentData &ed:_dataVtr){
        float diff = std::abs(ed.sampleTemp - temp);
        if (diff < minDiff) {
            minDiff = diff;
            resultData = ed;
        }
    }

    return resultData;
}

QString PointCalculate::textFormatNumbericalLabel(const QPointF point)
{
    return QString("数值：\n"
                   "%1℃,%2"
                   ).arg(QString::number(point.x(), 'f', 3))
            .arg(QString::number(point.y(), 'f', 3));
}

QString PointCalculate::textFormatStartPoint(const QPointF point)
{
    return QString("外推起始点：\n"
                   "%1℃"
                   ).arg(QString::number(point.x(), 'f', 3));
}

QString PointCalculate::textFormatEndPoint(const QPointF point)
{
    return QString("外推终止点：\n"
                   "%1℃"
                   ).arg(QString::number(point.x(), 'f', 3));
}

QPointF PointCalculate::getClosestPointByY(const double left,const double right,const double valueY)
{
    double minValue = std::numeric_limits<double>::infinity(); // 初始化为正无穷
    QPointF closestPoint;

    for (const Global::ExperimentData& ed : _dataVtr) {
        if (left < ed.sampleTemp && ed.sampleTemp < right) {
            double diff = std::abs(ed.dsc - valueY);
            if (diff < minValue) {
                minValue = diff;
                closestPoint = QPointF(ed.sampleTemp, ed.dsc);
            }
        }
    }

    return closestPoint;
}

QString PointCalculate::textFormatGlassTranstion(const float t1,const float tg,const float t2)
{
    return QString("T1：%1℃\n"
                   "Tg：%2℃\n"
                   "T2：%3℃"
                   )
            .arg(QString::number(t1, 'f', 3))
            .arg(QString::number(tg, 'f', 3))
            .arg(QString::number(t2, 'f', 3));
}


QPair<float, float> PointCalculate::getMaxMinValue()
{
    if (_dataVtr.isEmpty()) {
        return QPair<float, float>(0.0f, 0.0f);
    }

    float maxDsc = std::numeric_limits<float>::lowest(); // 初始化为最小浮点数
    float minDsc = std::numeric_limits<float>::max();    // 初始化为最大浮点数

    for(const Global::ExperimentData &ed : _dataVtr) {
        if (ed.dsc > maxDsc) {
            maxDsc = ed.dsc;
        }
        if (ed.dsc < minDsc) {
            minDsc = ed.dsc;
        }
    }

    return QPair<float, float>(minDsc, maxDsc);
}

QVector<Global::ExperimentData> PointCalculate::getDataInXRange(const float x1, const float x2)
{
    QVector<Global::ExperimentData> targetVtr;
    for(const Global::ExperimentData &ed : _dataVtr) {
        if(x1 < ed.sampleTemp && ed.sampleTemp < x2){
            targetVtr.push_back(ed);
        }else if (ed.sampleTemp > x2){
            break;
        }

    }

    return targetVtr;
}
QVector<QPointF> PointCalculate::movingAveragePoint(const QVector<QPointF> &points, int windowSize)
{
#if 0
    QVector<QPointF> result;
    int n = points.size();
    for (int i = 0; i < n; ++i) {
        double sumY = 0.0;
        double sumX = 0.0;
        int count = 0;
        for (int j = std::max(0, i - windowSize / 2); j <= std::min(n - 1, i + windowSize / 2); ++j) {
            sumY += points[j].y();
            sumX += points[j].x();
            count++;
        }
        if (count > 0) {
            double avgY = sumY / count;
            double avgX = sumX / count;
            result.append(QPointF(avgX, avgY));
        }
    }
    return result;
#endif
    QVector<QPointF> result;
    int n = points.size();
    for (int i = 0; i < n; ++i) {
        double sumY = 0.0;
        int count = 0;
        for (int j = std::max(0, i - windowSize / 2); j <= std::min(n - 1, i + windowSize / 2); ++j) {
            sumY += points[j].y();
            count++;
        }
        if (count > 0) {
            double avgY = sumY / count;
            result.append(QPointF(points[i].x(), avgY)); // 使用原始的 x 值
        }
    }
    return result;
}
QVector<QPointF> PointCalculate::getNearbyPointGroupByX(const float targetX)
{
    const int conCount = 10;
    QVector<QPointF> tmpPointVtr,targetPointVtr;
    float minDiff = std::numeric_limits<float>::max();

    for(Global::ExperimentData &ed:_dataVtr){
        float diff = std::abs(ed.sampleTemp - targetX);
        if(diff > 10){
            continue;
        }

        tmpPointVtr.push_back({ed.sampleTemp,ed.dsc});

        if (diff < minDiff) {
            minDiff = diff;

            if(tmpPointVtr.size() > conCount){
                targetPointVtr = QVector<QPointF>(tmpPointVtr.end() - conCount, tmpPointVtr.end());
            }else{
                targetPointVtr = tmpPointVtr;
            }
        }
    }

    return targetPointVtr;
}

// 计算两点之间的斜率
double PointCalculate::calculateSlope(double x1, double y1, double x2, double y2) {
    if(x1 == x2){
        return 0.0;
    }
    return (y2 - y1) / (x2 - x1);
}

// 寻找拐点
QVector<double> PointCalculate::findInflectionPoints(
        const QVector<double>& x, const QVector<double>& y) {
    QVector<double> inflectionPointsX;
    for (int i = 2; i < x.size() - 2; ++i) {
        double d1 = calculateSlope(x[i - 2], y[i - 2], x[i - 1], y[i - 1]);
        double d2 = calculateSlope(x[i - 1], y[i - 1], x[i], y[i]);
        double d3 = calculateSlope(x[i], y[i], x[i + 1], y[i + 1]);
        double d4 = calculateSlope(x[i + 1], y[i + 1], x[i + 2], y[i + 2]);

        // 检查二阶导数的符号变化
        if (((d2 - d1) * (d3 - d2) < 0) && ((d3 - d2) * (d4 - d3) < 0)) {
            inflectionPointsX.append(x[i]);
        }
    }
    return inflectionPointsX;
}

// 计算切线方程
QMap<double, PointCalculate::Line>  PointCalculate::calculateTangentLine(
        const QVector<double>& x, const QVector<double>& y) {
    QMap<double, Line> tangentLines;
    QVector<double> inflectionPointsX = findInflectionPoints(x, y);

    for (double xInflection : inflectionPointsX) {
        int i = std::distance(x.begin(), std::find(x.begin(), x.end(), xInflection));
        double slope = calculateSlope(x[i - 1], y[i - 1], x[i + 1], y[i + 1]);
        if(slope == 0.0){
            continue;
        }
        double yInflection = y[i];
        double intercept = yInflection - slope * xInflection;
        tangentLines[xInflection] = {slope, intercept};
    }

    return tangentLines;
}

QPair<float, float> PointCalculate::getTheMaximumAndMinimumValuesOfTime(
        const double min,const double max)
{

    float sampleTempMax = std::numeric_limits<float>::min();
    float sampleTempMin = std::numeric_limits<float>::max();

    float runTimeMax = std::numeric_limits<float>::min();
    float runTimeMin = std::numeric_limits<float>::max();

    for(Global::ExperimentData& ed:_dataVtr){
        if(ed.sampleTemp > sampleTempMax){
            sampleTempMax = ed.sampleTemp;
        }
        if(ed.sampleTemp < sampleTempMin){
            sampleTempMin = ed.sampleTemp;
        }
        if(ed.runTime > runTimeMax){
            runTimeMax  = ed.runTime;
        }
        if(ed.runTime < runTimeMin){
            runTimeMin = ed.runTime;
        }
    }

    //
    double tempDiff = max - min;

    double dataTempDiff = sampleTempMax - sampleTempMin;

    double dataTimeDiff  = runTimeMax - runTimeMin;

    // timeDiff / dataTimeDiff = tempDiff / dataTempDiff;
    double timeDiff = tempDiff * dataTimeDiff / dataTempDiff;

    return qMakePair<float,float>(0.0,timeDiff);
}

QVector<QPointF> PointCalculate::getPointVtrInXRange(const float x1, const float x2)
{
    QVector<QPointF> targetVtr;
    for(const Global::ExperimentData &ed : _dataVtr) {
        if(x1 < ed.sampleTemp && ed.sampleTemp < x2){
            targetVtr.push_back({ed.sampleTemp,ed.dsc});
        }else if (ed.sampleTemp > x2){
            break;
        }
    }

    return targetVtr;
}

QString PointCalculate::textFormatPeakPointWithTime(const float enthalpyValue, const float peakValue, const float startPoint, const float endPoint)
{
    return QString("峰的综合信息：\n"
                   "焓值：%1 J/g \n"
                   "峰值：%2min \n"
                   "起始点：%3min \n"
                   "终止点：%4min"
                   )
            .arg(QString::number(enthalpyValue, 'f', 4))
            .arg(QString::number(peakValue, 'f', 3))
            .arg(QString::number(startPoint, 'f', 3))
            .arg(QString::number(endPoint, 'f', 3));
}

double PointCalculate::obtainTimeValueBasedOnTemperatureValue(const double sampleTemp)
{
    double minDiff = std::numeric_limits<float>::max();
    double targetValue = 0.0;

    for(const Global::ExperimentData &ed : _dataVtr) {
        double min = std::abs(ed.sampleTemp - sampleTemp);
        if (min < minDiff) {
            minDiff = min;
            targetValue = ed.runTime;
        }
    }

    return targetValue;
}
QPair<float, float> PointCalculate::getMinAndMaxOfAxis(const float min, const float max)
{
    double diff  = max - min;
    double center = diff / 2;
    return qMakePair<float,float>(min - diff * 0.2,
                                  max + diff * 0.2);
}
QPair<float, float> PointCalculate::getMinAndMaxOfSampleTemp()
{
    float sampleTempMax = std::numeric_limits<float>::min();
    float sampleTempMin = std::numeric_limits<float>::max();

    for(Global::ExperimentData& ed:_dataVtr){
        if(ed.sampleTemp > sampleTempMax){
            sampleTempMax = ed.sampleTemp;
        }
        if(ed.sampleTemp < sampleTempMin){
            sampleTempMin = ed.sampleTemp;
        }
    }

    return qMakePair<float,float>(sampleTempMin,sampleTempMax);
}

QPair<Global::ExperimentData, Global::ExperimentData> PointCalculate::calculateStartAndEndData()
{
    QPair<QPointF,QPointF> leftAndRightPair = calculateStartAndEndPoint();

    ExperimentData leftEd =  getClosestDataByTemperature(leftAndRightPair.first.x());
    ExperimentData rightEd =  getClosestDataByTemperature(leftAndRightPair.second.x());

    return qMakePair<Global::ExperimentData, Global::ExperimentData> (leftEd,rightEd);
}

QPair<float, float> PointCalculate::getMinAndMaxOfRunTime()
{
    float runTimeMax = std::numeric_limits<float>::min();
    float runTimeMin = std::numeric_limits<float>::max();

    for(Global::ExperimentData& ed:_dataVtr){
        if(ed.runTime > runTimeMax){
            runTimeMax  = ed.runTime;
        }
        if(ed.runTime < runTimeMin){
            runTimeMin = ed.runTime;
        }
    }

    return qMakePair<float,float>(runTimeMin,runTimeMax);
}
Global::ExperimentData PointCalculate::findOnSetDataByTemperature(const double x1,const double x2)
{
    Global::ExperimentData resultEd;

    QVector<Global::ExperimentData> edVtr = getDataInXRange(x1,x2);
    if(edVtr.empty()){
        return resultEd;
    }

    double maxDsc = std::numeric_limits<float>::min();
    for(Global::ExperimentData& ed:edVtr){
        if(ed.dsc > maxDsc){
            maxDsc = ed.dsc;
        }
    }

    // 从后往前遍历，找到第一个 dsc 与 standardDsc 相等的 ExperimentData
    for (auto it = edVtr.rbegin(); it != edVtr.rend(); ++it) {
        if(std::abs(it->dsc - maxDsc) < Global::OnsetAndEndSetRate * maxDsc){
            resultEd =  *it; // 找到匹配项，返回该值
            break;
        }
    }

    return resultEd;
}

Global::ExperimentData PointCalculate::findEndSetDataByTemperature(const double x1, const double x2)
{
    Global::ExperimentData resultEd;

    QVector<Global::ExperimentData> edVtr = getDataInXRange(x1,x2);
    if(edVtr.empty()){
        return resultEd;
    }

    double maxDsc = std::numeric_limits<float>::min();
    for(Global::ExperimentData& ed:edVtr){
        if(ed.dsc > maxDsc){
            maxDsc = ed.dsc;
        }
    }

    // 从后往前遍历，找到第一个 dsc 与 standardDsc 相等的 ExperimentData
    for (auto it = edVtr.begin(); it != edVtr.end(); ++it) {
        if(std::abs(it->dsc - maxDsc) < Global::OnsetAndEndSetRate * maxDsc){
            resultEd =  *it; // 找到匹配项，返回该值
            break;
        }
    }

    return resultEd;
}

QPair<float, float> PointCalculate::getMinAndMaxOfDSC()
{
    float dscMax = std::numeric_limits<float>::min();
    float dscMin = std::numeric_limits<float>::max();

    for(Global::ExperimentData& ed:_dataVtr){
        if(ed.dsc > dscMax){
            dscMax  = ed.dsc;
        }
        if(ed.dsc < dscMin){
            dscMin = ed.dsc;
        }
    }

    return qMakePair<float,float>(dscMin,dscMax);
}

QString PointCalculate::textFormatNumbericalLabelWithTime(const QPointF point)
{
    return QString("数值：\n"
                   "%1 min,%2"
                   ).arg(QString::number(point.x(), 'f', 3))
            .arg(QString::number(point.y(), 'f', 3));
}

QString PointCalculate::textFormatStartPointWithTime(const QPointF point)
{
    return QString("外推起始点：\n"
                   "%1 min"
                   ).arg(QString::number(point.x(), 'f', 3));
}

QString PointCalculate::textFormatEndPointWithTime(const QPointF point)
{
    return QString("外推终止点：\n"
                   "%1 min"
                   ).arg(QString::number(point.x(), 'f', 3));
}

QString PointCalculate::textFormatGlassTranstionWithTime(const float t1, const float tg, const float t2)
{
    return QString("T1：%1 min\n"
                   "Tg：%2 min\n"
                   "T2：%3 min"
                   )
            .arg(QString::number(t1, 'f', 3))
            .arg(QString::number(tg, 'f', 3))
            .arg(QString::number(t2, 'f', 3));
}

Global::ExperimentData PointCalculate::findOnSetDataByTime(const double x1, const double x2)
{
    QVector<Global::ExperimentData> edVtr;
    for(const Global::ExperimentData &ed : _dataVtr) {
        if(x1 < ed.runTime && ed.runTime < x2){
            edVtr.push_back(ed);
        }else if (ed.runTime > x2){
            break;
        }
    }

    Global::ExperimentData resultEd;
    if(!edVtr.empty()){
        resultEd = edVtr.last();
    }else{
        logde<<"edVtr empty...";
        return resultEd;
    }

    double maxDsc = std::numeric_limits<float>::min();
    for(Global::ExperimentData& ed:edVtr){
        if(ed.dsc > maxDsc){
            maxDsc = ed.dsc;
        }
    }

    // 从后往前遍历，找到第一个 dsc 与 standardDsc 相等的 ExperimentData
    for (auto it = edVtr.rbegin(); it != edVtr.rend(); ++it) {
        if(std::abs(it->dsc - maxDsc) < Global::OnsetAndEndSetRate * maxDsc){
            resultEd =  *it; // 找到匹配项，返回该值
            break;
        }
    }

    return resultEd;
}

Global::ExperimentData PointCalculate::getOITStartData(const double x1,const double x2)
{

    Global::ExperimentData startEd = _dataVtr.first();

    logde<<"startEd phase index:"<<startEd.phaseIndex;

    Global::ExperimentData edSelectTimeX2 = getClosestDataByTime(x2);
    logde<<"edSelectTimeX2 phase index:"<<edSelectTimeX2.phaseIndex;

    for(const Global::ExperimentData &ed : _dataVtr) {
        if(ed.phaseIndex == edSelectTimeX2.phaseIndex){
            startEd = ed;
            break;
        }
    }

    return startEd;
}

Global::ExperimentData PointCalculate::getClosestDataByTime(const float time)
{
    ExperimentData resultData;

    float minDiff = std::numeric_limits<float>::max();

    for(Global::ExperimentData &ed:_dataVtr){
        float diff = std::abs(ed.runTime - time);
        if (diff < minDiff) {
            minDiff = diff;
            resultData = ed;
        }
    }

    return resultData;
}

Global::ExperimentData PointCalculate::findEndSetDataByTime(const double x1, const double x2)
{
    Global::ExperimentData resultEd;

    //    QVector<Global::ExperimentData> edVtr = getDataInXRange(x1,x2);
    //    if(edVtr.empty()){
    //        return resultEd;
    //    }

    QVector<Global::ExperimentData> edVtr;
    for(const Global::ExperimentData &ed : _dataVtr) {
        if(x1 < ed.runTime && ed.runTime < x2){
            edVtr.push_back(ed);
        }else if (ed.runTime > x2){
            break;
        }
    }

    double maxDsc = std::numeric_limits<float>::min();
    for(Global::ExperimentData& ed:edVtr){
        if(ed.dsc > maxDsc){
            maxDsc = ed.dsc;
        }
    }

    // 从后往前遍历，找到第一个 dsc 与 standardDsc 相等的 ExperimentData
    for (auto it = edVtr.begin(); it != edVtr.end(); ++it) {
        if(std::abs(it->dsc - maxDsc) < Global::OnsetAndEndSetRate * maxDsc){
            resultEd =  *it; // 找到匹配项，返回该值
            break;
        }
    }

    return resultEd;
}

QPair<QPointF,QPointF>
PointCalculate::calculateOITStartAndEndDataByTime(const double x1, const double x2)
{
    // 获取起点数据。
    Global::ExperimentData startData = getOITStartData(x1,x2);
    //
    ExperimentData selectedData = getClosestDataByTime(x1);
    if(Global::isEqual(OITAutoAnalysis::getInstance()->ConDefaultXValue,x1)){
        selectedData = calculateMedianOIT().second;
    }

    QPair<Global::ExperimentData,Global::ExperimentData> maxDiffDataPair =
            calculateMaxDiffDataByTime(x1,x2);
    Global::ExperimentData endData;

    // calculate intersection point.
    QPointF selectedPoint1(selectedData.runTime,selectedData.dsc);
    QPointF selectedPoint2(selectedData.runTime + 10,selectedData.dsc);
    QPointF maxDiffPoint1(maxDiffDataPair.first.runTime,maxDiffDataPair.first.dsc);
    QPointF maxDiffPoint2(maxDiffDataPair.second.runTime,maxDiffDataPair.second.dsc);
    QPointF intersectionPoint = calculateIntersection(selectedPoint1,selectedPoint2,
                                                      maxDiffPoint1,maxDiffPoint2);

    return qMakePair(QPointF(startData.runTime,startData.dsc),
                     intersectionPoint);
}

QPair<Global::ExperimentData, Global::ExperimentData>
PointCalculate::calculateMaxDiffDataByTime(
        const double x1,const double x2)
{
    QVector<Global::ExperimentData> rangeEdVtr;
    for(const Global::ExperimentData &ed : _dataVtr) {
        if(x1 < ed.runTime && ed.runTime < x2){
            rangeEdVtr.push_back(ed);
        }else if (ed.runTime > x2){
            break;
        }
    }

    //
    float maxDiff = std::numeric_limits<float>::min();
    Global::ExperimentData targetCurrentData,targetLastPointData;
    for(int i = 0; i < rangeEdVtr.size() - 1;i++){
        Global::ExperimentData currentData = rangeEdVtr.at(i);
        Global::ExperimentData lastPointData = rangeEdVtr.at(i+1);

        double diff = std::abs(lastPointData.dsc - currentData.dsc);
        if(diff > maxDiff){
            maxDiff = diff;

            targetCurrentData = currentData;
            targetLastPointData = lastPointData;
        }
    }

    return qMakePair(targetCurrentData,targetLastPointData);

#if 0
    float maxDiff = std::numeric_limits<float>::min();
    QPointF currentPoint,lastPoint;

    for (int i = 0; i < _dataVtr.size() - 1; ++i) {
        const float currentTime = _dataVtr.at(i).sampleTemp;
        const float currentY = _dataVtr.at(i).dsc;

        //        if(type == MaxDiffPointDetailType::Left){
        //            if(currentX <= _leftSelectedPoint.x()){
        //                continue;
        //            }
        //            if(currentX >= _peakPoint.x()){
        //                break;
        //            }
        //        }else{
        if(currentTime <= _peakPoint.x()){
            continue;
        }
        if(currentTime >= _rightSelectedPoint.x()){
            break;
        }
        //        }
        //
        const float lastX = _dataVtr.at(i + 1).sampleTemp;
        const float lastY = _dataVtr.at(i + 1).dsc;
        float diff = std::abs(currentY - lastY);
        if(diff > maxDiff){
            maxDiff = diff;

            currentPoint.setX(currentTime);
            currentPoint.setY(currentY);
            lastPoint.setX(lastX);
            lastPoint.setY(lastY);
        }
    }

    return qMakePair(currentPoint,lastPoint);
#endif
}

// 返回值: first=true表示计算成功，second是中位数
std::pair<bool, Global::ExperimentData> PointCalculate::calculateMedianOIT(){
    ExperimentData ed;
    if (_dataVtr.empty()) return std::make_pair(false, ed);

    // 创建数据副本用于排序
    std::vector<ExperimentData> sortedData(_dataVtr.begin(),_dataVtr.end());

    // 定义排序比较函数，使用value成员进行比较
    auto compare = [](const ExperimentData& a, const ExperimentData& b) {
        return a.dsc < b.dsc;
    };

    // 对数据进行排序
    std::sort(sortedData.begin(), sortedData.end(), compare);

    // 计算中位数
    size_t n = sortedData.size();
    if (n % 2 == 0) {
        // 数据个数为偶数，中位数是中间两个数的平均值
        return std::make_pair(true, sortedData[n/2 - 1]);
    } else {
        // 数据个数为奇数，中位数是中间的数
        return std::make_pair(true, sortedData[n/2]);
    }
}


double PointCalculate::calculateDistance(const QPointF& p1, const QPointF& p2) {
    return std::sqrt(std::pow(p2.x() - p1.x(), 2) + std::pow(p2.y() - p1.y(), 2));
}

QVector<Global::ExperimentData> PointCalculate::getDataInXRangeByTime(const float x1, const float x2)
{
    QVector<Global::ExperimentData> targetVtr;
    for(const Global::ExperimentData &ed : _dataVtr) {
        if(x1 < ed.runTime && ed.runTime < x2){
            targetVtr.push_back(ed);
        }else if (ed.runTime > x2){
            break;
        }

    }

    return targetVtr;
}


QVector<QPointF> PointCalculate::getPeakPointGroupByTime(const double x1, const double x2)
{
    // modify select point.
    ExperimentData edX1 = getClosestDataByTime(x1);
    ExperimentData edX2 = getClosestDataByTime(x2);

    _leftSelectedPoint = QPointF(edX1.runTime,edX1.dsc);
    _rightSelectedPoint = QPointF(edX2.runTime,edX2.dsc);

    // 焓值计算还得用样品温度作为x值。
    QVector<QPointF> pointVtr;
    for(Global::ExperimentData& ed:_dataVtr)   {
        if(ed.sampleTemp >= edX1.sampleTemp &&
                ed.sampleTemp <= edX2.sampleTemp){

            pointVtr.push_back(QPointF(ed.sampleTemp,ed.dsc));
        }
    }

    return pointVtr;
}


QPair<QPointF, QPointF> PointCalculate::getSelectedPoints()
{
    return qMakePair<QPointF,QPointF>(_leftSelectedPoint,_rightSelectedPoint);
}

QPointF PointCalculate::getPeakPointByTime()
{
    int n = _dataVtr.size();

    if (n < 3) {
        return QPointF(); // 至少需要三个点才能找到波峰
    }

    QPointF uniquePeak;
    float maxDiff = -std::numeric_limits<float>::infinity();

    for (int i = 0; i < n; ++i) {
        const float currentX = _dataVtr.at(i).runTime;
        const float currentY = _dataVtr.at(i).dsc;

        if (currentX < _leftSelectedPoint.x()) {
            continue;
        }
        if (currentX > _rightSelectedPoint.x()) {
            break;
        }

        // 计算当前点与左选择点 y 值的差值
        float diffLeft = std::abs(currentY - _leftSelectedPoint.y());
        // 计算当前点与右选择点 y 值的差值
        float diffRight = std::abs(currentY - _rightSelectedPoint.y());
        // 取两个差值中的较大值
        float currentDiff = std::max(diffLeft, diffRight);

        if (currentDiff > maxDiff) {
            maxDiff = currentDiff;
            uniquePeak = QPointF(currentX, currentY);
        }
    }

    _peakPoint = uniquePeak;

    //    logde<<"peakPoint:"<<_peakPoint.x()<<","<<_peakPoint.y();

    return uniquePeak;
}
