#include <QHBoxLayout>
#include <QRandomGenerator>
#include <cmath>
#include <limits>
#include <qcustomplot.h>

#include "centralwidget.h"
#include "filemanager.h"
#include "peakpoint.h"
#include "logger.h"

CentralWidget::CentralWidget(QWidget *parent)
    : QWidget(parent),
      _customPlot(new QCustomPlot(this))
    ,_nanlysisMode(AnalysisMode::None)
{
    setMouseTracking(true);

    setStyleSheet("background-color: lightgray;");
    resize(888, 666);

    QHBoxLayout *layout = new QHBoxLayout();
    layout->setMargin(0);
    layout->addWidget(_customPlot);
    this->setLayout(layout);

    // 创建两条竖线
    _line1 = new QCPItemStraightLine(_customPlot);
    _line1->point1->setCoords(20, _customPlot->yAxis->range().lower);
    _line1->point2->setCoords(20, _customPlot->yAxis->range().upper);
    _line1->setPen(QPen(Qt::red));
    _line1->setSelectable(true);

    _line2 = new QCPItemStraightLine(_customPlot);
    _line2->point1->setCoords(40, _customPlot->yAxis->range().lower);
    _line2->point2->setCoords(40, _customPlot->yAxis->range().upper);
    _line2->setPen(QPen(Qt::red));
    _line2->setSelectable(true);

    // 安装事件过滤器
    _graph = _customPlot->addGraph(0);
    _eventHandler = new DragLineHandler(_customPlot, _line1, _line2, _graph, nullptr);
    _customPlot->installEventFilter(_eventHandler);

    connect(_eventHandler,&DragLineHandler::sigSendLineXCoord,
            this,&CentralWidget::sigSendLineXCoord);

    setEventHandlerEnable(false);
    //
#if 0
    // init data
    QVector<double> x(101), y(101);
    for (int i = 0; i < 101; i++) {
        x[i] = i / 50.0 - 1;//设置x的范围为-1~1
        y[i] = x[i] * x[i];
    }

    _customPlot->graph(0)->setData(x, y);
    //设置坐标轴标签
    _customPlot->xAxis->setLabel("x coordinates");
    _customPlot->yAxis->setLabel("y coordinates");
    //设置坐标轴范围，以便我们可以看到全部数据
    _customPlot->xAxis->setRange(0, 1);
    _customPlot->yAxis->setRange(0, 100);
    _customPlot->replot();
#endif
    //    startTimer(1000);
}

CentralWidget::~CentralWidget()
{
    FileManager::close();
}

void CentralWidget::setAnalysisMode(const CentralWidget::AnalysisMode mode)
{
#if 0
    if(_nanlysisMode == mode){
        return;
    }else{
        _nanlysisMode = mode;
    }
#endif
    _nanlysisMode = mode;

    switch (mode)
    {
    case AnalysisMode::NumericalLabel:
    case AnalysisMode::StartPoint:
    case AnalysisMode::StopPoint:
    case AnalysisMode::PeakSynthesisAnalysis:
        setEventHandlerEnable(true);
        break;
    default:
        break;
    }
}

void CentralWidget::slotModeModify(const Global::Mode mode)
{
    if (Global::Mode::ExperimentStart == mode)
    {
        if (_customPlot->graphCount() > 0 && _graph)
        {
            // 清除第一个图表上的数据
            _graph->setData(QVector<double>(), QVector<double>());
        }

        // 创建画布,设置画布上的点数据
        //        _graph = _customPlot->addGraph();

        // 设置坐标轴标签
        _customPlot->xAxis->setLabel("Temp/℃");
        _customPlot->yAxis->setLabel("DSC/mW");
        // 设置坐标轴范围，以便我们可以看到全部数据
        _customPlot->xAxis->setRange(0, 400);
        _customPlot->yAxis->setRange(-20, 20);
    }
    else if (Global::Mode::Analysis == mode)
    {
        qDebug() << "file close...";
        FileManager::close();
    }
}

void CentralWidget::slotRecvCommonData(const CommonData &cd)
{
    qDebug() << "slotRevCommonData";

    _customPlot->graph(0)->addData(cd.sample_temp, cd.dsc); // 添加数据到曲线
    _customPlot->replot();
    _customPlot->rescaleAxes();
    //
    FileManager::writeExperimentFile(cd);
}

void CentralWidget::slotRecvAnalysisFileName(const QString &fileName)
{
    qDebug() << "slotRecvAnalysisFileName" << fileName;

    //    QVector<FileManager::ExperimentData> dataVtr;
    _dataVtr.clear();
    FileManager::readExperimentFile(fileName, _dataVtr);

    if (_dataVtr.size() < 0)
    {
        return;
    }

    PeakPoint::setExperimentData(_dataVtr);

    // 设置坐标轴标签
    _customPlot->yAxis->setLabel("DSC/mW");
    _customPlot->xAxis->setLabel("Temp/℃");
    // 设置坐标轴范围，以便我们可以看到全部数据
    _customPlot->xAxis->setRange(0, 500);
    _customPlot->yAxis->setRange(-20, 20);

    QVector<double> xVtr, yVtr;
    for (FileManager::ExperimentData &ed : _dataVtr)
    {
        xVtr.push_back(ed.sampleTemp);
        yVtr.push_back(ed.dsc);
    }

    // 清除第一个图表上的数据
    if (_customPlot->graphCount() > 0 && _graph)
    {
        // 清除第一个图表上的数据
        _graph->setData(QVector<double>(), QVector<double>());
    }

    _graph->addData(xVtr, yVtr);
    _customPlot->replot();
}

void CentralWidget::slotAnalysisSettingApply()
{
    switch (_nanlysisMode) {
    case AnalysisMode::NumericalLabel:
    {
        QPointF selectPoint = PeakPoint::findClosestPointByX(
                    _line1->point1->coords().x());

        drawText(selectPoint,PeakPoint::textFormatNumbericalLabel(selectPoint));

        break;
    }
    case AnalysisMode::PeakSynthesisAnalysis:
    {
        double x1 = _line1->point1->coords().x();
        double x2 = _line2->point1->coords().x();

        fillGraph(x1,x2);

        PeakPoint::setRegionPointX(x1,x2);

        //enthalpy
        double enthalpyValue = PeakPoint::calculateArea();
        //peak
        QPointF peakPoint = PeakPoint::findPeakPoint();
        //        qDebug()<<"peak point:"<<point;
        //start point and end point
        QPair<QPointF, QPointF> startEndPointPair =
                PeakPoint::calculateStartAndEndPoint();

        drawText(peakPoint,PeakPoint::textFormatPeakPoint(enthalpyValue,
                                                          peakPoint.x(),
                                                          startEndPointPair.first.x(),
                                                          startEndPointPair.second.x()));
        //
        break;
    }
    default:
        break;
    }
}

void CentralWidget::slotAnalysisSettingConfirm()
{
    slotAnalysisSettingApply();
    setAnalysisMode(CentralWidget::AnalysisMode::None);
    _line1->setVisible(false);

    emit sigRightDockWidgetHide();
}

void CentralWidget::slotAnalysisSettingUndo()
{
    clearData(ClearDataMode::Undo);
}

void CentralWidget::slotAnalysisSettingCancel()
{
    clearData(ClearDataMode::Undo);
    setAnalysisMode(CentralWidget::AnalysisMode::None);
    _line1->setVisible(false);

    emit sigRightDockWidgetHide();
}

void CentralWidget::slotAnalysisSettingLineXPoint(const int index, const double)
{

}

void CentralWidget::timerEvent(QTimerEvent *event)
{
    // key的单位是秒
    double key = QDateTime::currentDateTime().toMSecsSinceEpoch() / 1000.0;
    // 添加数据
    // 使用随机数产生一条曲线
    // double value0 = realDataI();
    double value0 = QRandomGenerator::global()->bounded(10.123);
    _customPlot->graph(0)->addData(key, value0); // 添加数据到曲线

    // 删除8秒之前的数据。这里的8要和下面设置横坐标宽度的8配合起来
    // 才能起到想要的效果，可以调整这两个值，观察显示的效果。
    _customPlot->graph(0)->data()->remove(key - 80);
    // 自动设定graph(1)曲线y轴的范围，如果不设定，有可能看不到图像
    // 也可以用ui->customPlot->yAxis->setRange(up,low)手动设定y轴范围
    _customPlot->graph(0)->rescaleValueAxis(true);

    // 这里的8，是指横坐标时间宽度为8秒，如果想要横坐标显示更多的时间
    // 就把8调整为比较大到值，比如要显示60秒，那就改成60。
    // 这时removeDataBefore(key-8)中的8也要改成60，否则曲线显示不完整。

    _customPlot->yAxis->setRange(0, 20);                          // 设定x轴的范围
    _customPlot->xAxis->setRange(key + 0.25, 80, Qt::AlignRight); // 设定x轴的范围
    _customPlot->replot();
}

void CentralWidget::contextMenuEvent(QContextMenuEvent *event)
{
    qDebug()<<"left menu...";
    QPoint point =  event->globalPos();
    emit sigContextMenuShow(point);
}

void CentralWidget::setEventHandlerEnable(const bool flag)
{
    logde<<"setEventHandlerEnable..."<<flag;

    // todo. 当竖线隐藏时，需要设置不可选择模式。
    _eventHandler->setEnable(flag);

    _line1->setVisible(flag);
    if(AnalysisMode::NumericalLabel != _nanlysisMode){
        _line2->setVisible(flag);
    }
    _customPlot->replot();
}

void CentralWidget::drawText(const QPointF point, const QString text)
{
    //    double y = PeakPoint::findClosestY(x);
    // 创建标注文字（QCPItemText）
    QCPItemText *textLabel = new QCPItemText(_customPlot);
    textLabel->setPositionAlignment(Qt::AlignBottom | Qt::AlignHCenter);  // 对齐方式
    textLabel->position->setType(QCPItemPosition::ptPlotCoords);        // 使用数据坐标
    textLabel->position->setCoords(point.x() + 20, point.y());  // 设置文本位置在指定点上方

    textLabel->setText(text);  // 设置文本内容
    //    textLabel->setFont(QFont("Arial", 10));
    textLabel->setPen(QPen(Qt::lightGray));  // 文字边框
    textLabel->setBrush(Qt::white);      // 文字背景

    // 创建指向点的线段（QCPItemLine）
    QCPItemLine *arrow = new QCPItemLine(_customPlot);
    arrow->start->setParentAnchor(textLabel->left);  // 线段起点绑定到标注文字底部
    arrow->end->setCoords(point.x(),point.y());  // 线段终点设置为指定的点
    arrow->setHead(QCPLineEnding::esSpikeArrow);  // 添加箭头
    arrow->setPen(QPen(Qt::red, 1));

    // 重绘图表以显示文本标签和箭头
    _customPlot->replot();

#if 0
    // 创建标注文字（QCPItemText）
    QCPItemText *textLabel = new QCPItemText(_customPlot);
    textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter);  // 对齐方式
    textLabel->position->setType(QCPItemPosition::ptPlotCoords);        // 使用数据坐标
    textLabel->position->setCoords(x,
                                   _graph->data()->at(x)->value + 0.5);  // 假设标注在 x=5 的点上方
    textLabel->setText("标注文字");
    textLabel->setFont(QFont("Arial", 10));
    textLabel->setPen(QPen(Qt::black));  // 文字边框
    textLabel->setBrush(Qt::white);      // 文字背景

    // 创建指向点的线段（QCPItemLine）
    QCPItemLine *arrow = new QCPItemLine(_customPlot);
    arrow->start->setParentAnchor(textLabel->bottom);  // 线段起点绑定到标注文字底部
    arrow->end->setCoords(x, _graph->data()->at(x)->value);  // 线段终点绑定到数据点
    arrow->setHead(QCPLineEnding::esSpikeArrow);  // 添加箭头
    arrow->setPen(QPen(Qt::red, 2));
#endif

#if 0
    if (!_graph || !_customPlot) {
        return;
    }
    // 创建标注文字（QCPItemText）
    QCPItemText *textLabel = new QCPItemText(_customPlot);
    textLabel->setPositionAlignment(Qt::AlignBottom|Qt::AlignHCenter);  // 对齐方式
    textLabel->position->setType(QCPItemPosition::ptPlotCoords);        // 使用数据坐标

    // 查找最接近 x 的数据点
    auto it = _graph->data()->findBegin(x);
    if (it != _graph->data()->end()) {
        double y = it->value + 0.5;
        textLabel->position->setCoords(x, y);
        textLabel->setText(text);
        textLabel->setFont(QFont("Arial", 10));
        textLabel->setPen(QPen(Qt::black));  // 文字边框
        textLabel->setBrush(Qt::white);      // 文字背景

        // 创建指向点的线段（QCPItemLine）
        QCPItemLine *arrow = new QCPItemLine(_customPlot);
        arrow->start->setParentAnchor(textLabel->bottom);  // 线段起点绑定到标注文字底部
        arrow->end->setCoords(x, it->value);  // 线段终点绑定到数据点
        arrow->setHead(QCPLineEnding::esSpikeArrow);  // 添加箭头
        arrow->setPen(QPen(Qt::red, 2));
    }
#endif

}

#if 0
double CentralWidget::findClosestY(double targetX) {
    // 获取曲线数据容器
    QSharedPointer<QCPDataContainer<QCPGraphData>> dataContainer =
            _graph->data();
    // 初始化最小差值和对应的 y 值
    double minDiff = std::numeric_limits<double>::max();
    double closestY = 0.0;

    // 遍历数据容器
    for (int i = 0; i < dataContainer->size(); ++i) {
        double currentX = dataContainer->at(i)->key;
        double currentY = dataContainer->at(i)->value;

        // 计算当前 x 与目标 x 的差值的绝对值
        double diff = std::abs(currentX - targetX);

        // 更新最小差值和对应的 y 值
        if (diff < minDiff) {
            minDiff = diff;
            closestY = currentY;
        }
    }

    return closestY;
}
#endif

void CentralWidget::fillGraph(const double x1, const double x2)
{
    //todo.未寻找x1\x2之间最大值。

    double y1 = PeakPoint::findClosestPointByX(x1).y();
    double y2 = PeakPoint::findClosestPointByX(x2).y();

    QVector<double> xVtr,yVtr;
    xVtr.push_back(x1);
    xVtr.push_back(x2);

    yVtr.push_back(y1);
    yVtr.push_back(y2);

    QCPGraph *mainGraph = _customPlot->addGraph();
    mainGraph->setData(xVtr, yVtr);

    // 样式配置
    mainGraph->setPen(QPen(Qt::red, 1));

    _graph->setBrush(QBrush(Qt::lightGray));
    _graph->setChannelFillGraph(mainGraph);

    //    customPlot->graph(0)->setChannelFillGraph(customPlot->graph(1));
    //    _customPlot->graph(1);
    _customPlot->replot();
}

void CentralWidget::clearData(const CentralWidget::ClearDataMode mode)
{
    if(mode == ClearDataMode::All){
        // Clear the data of graph.
        if (_customPlot->graphCount() > 0 && _graph)
        {
            _graph->setData(QVector<double>(), QVector<double>());
        }

        // Set lines visiable false.
        _line1->setVisible(false);
        _line2->setVisible(false);
    }

    // Clear filled area.
    _graph->setBrush(QBrush(Qt::transparent));

    // Clear graph on plot.
    for (int i = _customPlot->graphCount() - 1; i >= 0; --i) {
        QCPGraph *graph = _customPlot->graph(i);
        if (graph != _graph) {
            _customPlot->removeGraph(graph);
        }
    }
    // Delete items.
    QList<QCPAbstractItem *> itemsToKeep;
    itemsToKeep  << _line1 << _line2;

    for (int i = _customPlot->itemCount() - 1; i >= 0; --i) {
        QCPAbstractItem *item = _customPlot->item(i);
        if (!itemsToKeep.contains(item)) {
            _customPlot->removeItem(item);
        }
    }

    // 重绘图表以显示更改
    _customPlot->replot();
}

void CentralWidget::clearAllData()
{
    clearData(ClearDataMode::All);
}
