#include "PhaseWindow.h"
#include "ui_PhaseWindow.h"

#include <iostream>
#include <QTimer>
#include <QDateTime>
#include <QLabel>
#include <QGroupBox>
#include <QLineEdit>
#include <QPushButton>
#include <QHBoxLayout>
#include <QDesktopWidget>
#include <QThread>

PhaseWindow::PhaseWindow(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::PhaseWindow)
{
    ui->setupUi(this);

    // 无边框
    this->setWindowFlags(Qt::FramelessWindowHint);

    // 窗口大小为占满一屏
    QRect screenRect = QApplication::desktop()->availableGeometry();
    resize(screenRect.width(), screenRect.height());
    setWindowIcon(QIcon(":/images/PhaseComp.png"));
    setWindowState(Qt::WindowFullScreen);

    // 将窗口移动到左上角
    move(0, 0);
    ui->minButt->move(screenRect.width() - 80, 10);
    ui->endButt->move(screenRect.width() - 140, 10);
    ui->startButt->move(screenRect.width() - 200, 10);
    ui->line->setGeometry(0, 59, screenRect.width(), 1);

    trayIcon = new QSystemTrayIcon(this);
    trayIcon->setIcon(QIcon(":/images/PhaseComp.png"));
    trayIcon->setToolTip(QString("相位测量数据采集软件（%1）").arg(SettingConfig::getInstance().MASTER == 1 ? "主" : "备"));
    trayIcon->show();

    connect(trayIcon, &QSystemTrayIcon::activated, this, &PhaseWindow::onTrayIconActived);

    // 设置主体区域的大小和位置
    ui->scrollArea->setGeometry(0, 60, screenRect.width(), screenRect.height() - 60);
    ui->scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);

    ui->logo->setText(QString("相位测量数据采集软件——%1").arg(SettingConfig::getInstance().MASTER == 1 ? "主" : "备"));

    if (SettingConfig::getInstance().NEED_KAFKA == 1) {
        // kafka consumer
        kafkaConsumer = new QKafkaConsumer(this);
        kafkaConsumer->setBrokers(SettingConfig::getInstance().KAFKA_BROKERS);
        kafkaConsumer->setTopic(SettingConfig::getInstance().KAFKA_CMD_TOPIC);
        kafkaConsumer->createConsumer();
        kafkaConsumer->start();
        connect(kafkaConsumer, &QKafkaConsumer::messageRecieved, this, &PhaseWindow::onPhaseCommandReceived);
    }

    httpReq = new HttpRequestController(this);
    // 1. 获取访问接口需要的token
    int retCode = this->initHttpToken();
    if (retCode != 200)
    {
        QMessageBox::information(this, "错误", "获取http请求的token失败，程序即将退出");

        QTimer::singleShot(1000, qApp, SLOT(quit()));
    }
    // 2. 获取字典值：设备类型

    // 3. 获取比相仪设备列表
    initDeviceList();

    // 4. 打开串口
    for (int i = 0; i < deviceList.size(); i++) {
        PhaseDevice * devicePtr = deviceList.at(i);
        devicePtr->initSerialPort();
        devicePtr->startWork();

        QThread::msleep(100);
    }

    // 6. 绘制一个设备的多个通道数据面板
    this->generateWidgetForDevice();

    // 7. 启动监听
    HttpServer::instance().run(QHostAddress::Any, SettingConfig::getInstance().SERVER_PORT);

    // 8. 备路应用定时向主路应用请求以判定主路应用的状态
    if (SettingConfig::getInstance().MASTER == 0) {
        heartTimer = new QTimer();
        connect(heartTimer, &QTimer::timeout, this, &PhaseWindow::onPhaseMaserHeartHandle);
        heartTimer->start(1000);
    }
}

PhaseWindow::~PhaseWindow()
{
    delete ui;
}

void PhaseWindow::drawPhaseDataOnPage(PhaseDataDto * phaseData)
{
    // 当前显示的设备编号
    QString currentDevCode = ui->devSelect->currentData().toString();

    // 如果不是当前设备的帧，直接返回
    if (phaseData->devCode != currentDevCode)
    {
        return;
    }

    ui->labTm->setText(phaseData->timestamp.left(19));

    // 更新所有通道BOX的值
    for (int i = 0; i < phaseData->channelActive.size(); i++)
    {
        // 获取对应的通道BOX
        QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1);

        // 赋值，对应的lineEdit/label
        ((QLabel *)channelBox->children().at(1))->setText(phaseData->channelActive.at(i) == "1" ? "有效" : "无效"); // 有效性
        ((QLabel *)channelBox->children().at(2))->setText(phaseData->frameId); // 数据ID
        ((QLineEdit *)channelBox->children().at(4))->setText(QString("%1 s").arg(phaseData->channelDataStr.at(i))); // 测量数据值
    }
}

void PhaseWindow::drawPhaseAllenOnPage(QString devCode, QVector<QStringList> channelAllenResultStr)
{
    // 当前显示的设备编号
    QString currentDevCode = ui->devSelect->currentData().toString();

    // 如果不是当前设备的帧，直接返回
    if (devCode != currentDevCode)
    {
        return;
    }

    // 更新所有通道BOX的值
    for (int i = 0; i < channelAllenResultStr.size(); i++)
    {
        // 获取对应的通道BOX
        QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1);

        // 赋值，对应的label
        ((QLabel *)channelBox->children().at(7))->setText(channelAllenResultStr.at(i).at(0)); // tau=1 Allen
        ((QLabel *)channelBox->children().at(8))->setText(QString("(%1)").arg(channelAllenResultStr.at(i).at(1))); // tau=1 Count

        ((QLabel *)channelBox->children().at(10))->setText(channelAllenResultStr.at(i).at(2)); // tau=10 Allen
        ((QLabel *)channelBox->children().at(11))->setText(QString("(%1)").arg(channelAllenResultStr.at(i).at(3))); // tau=10 Count

        ((QLabel *)channelBox->children().at(13))->setText(channelAllenResultStr.at(i).at(4)); // tau=100 Allen
        ((QLabel *)channelBox->children().at(14))->setText(QString("(%1)").arg(channelAllenResultStr.at(i).at(5))); // tau=100 Count

        ((QLabel *)channelBox->children().at(16))->setText(channelAllenResultStr.at(i).at(6)); // tau=1000 Allen
        ((QLabel *)channelBox->children().at(17))->setText(QString("(%1)").arg(channelAllenResultStr.at(i).at(7))); // tau=1000 Count

        ((QLabel *)channelBox->children().at(19))->setText(channelAllenResultStr.at(i).at(8)); // tau=10000 Allen
        ((QLabel *)channelBox->children().at(20))->setText(QString("(%1)").arg(channelAllenResultStr.at(i).at(9))); // tau=10000 Count
    }
}

void PhaseWindow::generateWidgetForDevice()
{
    // 获取设备数据
    int channelNum = 16;

    QRect screenRect = QApplication::desktop()->screenGeometry();

    ui->scrollContents->setGeometry(0, 60, screenRect.width(), channelNum * 90);

    QVBoxLayout * layout = new QVBoxLayout(ui->scrollContents);
    const QFont labelFont("微软雅黑", 10);

    for (int i = 0; i < channelNum; i++)
    {
        QGroupBox * group = new QGroupBox(ui->scrollContents);
        group->setTitle(QString("通道 - %1").arg(i + 1));
        group->setFont(QFont("微软雅黑", 12));
        group->setGeometry(20, i * 80 + 10, screenRect.width() - 40, 80);

        QHBoxLayout * vbox = new QHBoxLayout(group);

        // index = 1
        QLabel * validLabel = new QLabel();
        validLabel->setText("-");
        validLabel->setFont(labelFont);
        validLabel->setStyleSheet("margin-left:20;");
        vbox->addWidget(validLabel);

        // index = 2
        QLabel * idLabel = new QLabel();
        idLabel->setText("0000");
        idLabel->setFont(labelFont);
        idLabel->setStyleSheet("margin-left:20;");
        vbox->addWidget(idLabel);

        // index = 3
        QLabel * dataLabel = new QLabel();
        dataLabel->setText("测量数据");
        dataLabel->setFont(labelFont);
        dataLabel->setStyleSheet("margin-left:20;");
        vbox->addWidget(dataLabel);
        // index = 4
        QLineEdit * dataValue = new QLineEdit();
        dataValue->setFixedWidth(200);
        dataValue->setFont(labelFont);
        vbox->addWidget(dataValue);

        // index = 5
        QLabel * perfLabel = new QLabel();
        perfLabel->setText("稳定度");
        perfLabel->setFont(labelFont);
        perfLabel->setStyleSheet("margin-left:50;");
        vbox->addWidget(perfLabel);

        // index = 6
        QLabel * oneLabel = new QLabel();
        oneLabel->setText("Tau(s)=1");
        oneLabel->setFont(labelFont);
        oneLabel->setStyleSheet("margin-left:20;");
        vbox->addWidget(oneLabel);
        // index = 7
        QLabel * oneAllen = new QLabel();
        oneAllen->setText("0.00");
        oneAllen->setFont(labelFont);
        vbox->addWidget(oneAllen);
        // index = 8
        QLabel * oneCount = new QLabel();
        oneCount->setText("0");
        oneCount->setFont(labelFont);
        vbox->addWidget(oneCount);

        // index = 9
        QLabel * tenLabel = new QLabel();
        tenLabel->setText("Tau(s)=10");
        tenLabel->setFont(labelFont);
        tenLabel->setStyleSheet("margin-left:20;");
        vbox->addWidget(tenLabel);
        // index = 10
        QLabel * tenAllen = new QLabel();
        tenAllen->setText("0.00");
        tenAllen->setFont(labelFont);
        vbox->addWidget(tenAllen);
        // index = 11
        QLabel * tenCount = new QLabel();
        tenCount->setText("0");
        tenCount->setFont(labelFont);
        vbox->addWidget(tenCount);

        // index = 12
        QLabel * hundLabel = new QLabel();
        hundLabel->setText("Tau(s)=100");
        hundLabel->setFont(labelFont);
        hundLabel->setStyleSheet("margin-left:20;");
        vbox->addWidget(hundLabel);
        // index = 13
        QLabel * hundAllen = new QLabel();
        hundAllen->setText("0.00");
        hundAllen->setFont(labelFont);
        vbox->addWidget(hundAllen);
        // index = 14
        QLabel * hundCount = new QLabel();
        hundCount->setText("0");
        hundCount->setFont(labelFont);
        vbox->addWidget(hundCount);

        // index = 15
        QLabel * thouLabel = new QLabel();
        thouLabel->setText("Tau(s)=1000");
        thouLabel->setFont(labelFont);
        thouLabel->setStyleSheet("margin-left:20;");
        vbox->addWidget(thouLabel);
        // index = 16
        QLabel * thouAllen = new QLabel();
        thouAllen->setText("0.00");
        thouAllen->setFont(labelFont);
        vbox->addWidget(thouAllen);
        // index = 17
        QLabel * thouCount = new QLabel();
        thouCount->setText("0");
        thouCount->setFont(labelFont);
        vbox->addWidget(thouCount);

        // index = 18
        QLabel * ttLabel = new QLabel();
        ttLabel->setText("Tau(s)=10000");
        ttLabel->setFont(labelFont);
        ttLabel->setStyleSheet("margin-left:20;");
        vbox->addWidget(ttLabel);
        // index = 19
        QLabel * ttAllen = new QLabel();
        ttAllen->setText("0.00");
        ttAllen->setFont(labelFont);
        vbox->addWidget(ttAllen);
        // index = 20
        QLabel * ttCount = new QLabel();
        ttCount->setText("0");
        ttCount->setFont(labelFont);
        vbox->addWidget(ttCount);

        QSpacerItem * hSpace = new QSpacerItem(20, 20);
        hSpace->changeSize(20, 20, QSizePolicy::Expanding);
        vbox->addItem(hSpace);

        group->setLayout(vbox);

        layout->addWidget(group);
    }
}

int PhaseWindow::initHttpToken()
{
    QJsonObject response = httpReq->getTokenByClientId(SettingConfig::getInstance().CLIENT_ID,
                                                       SettingConfig::getInstance().APP_KEY);
    return response.find("code")->toInt();
}

void PhaseWindow::initDeviceList()
{
    QJsonObject devListRes = httpReq->initDeviceList(SettingConfig::getInstance().DEV_TYPES, SettingConfig::getInstance().SYSTEM);
    if (devListRes.find("code")->toInt() == 200)
    {
        ui->devSelect->clear();

        // 4. 将获取到的设备添加到下拉列表框中
        QJsonArray devArray = devListRes.value("data").toArray();
        for (int i = 0; i < devArray.size(); i++)
        {
            QJsonObject devItem = devArray.at(i).toObject();
            ui->devSelect->addItem(devItem.value("deviceName").toString(), devItem.value("deviceNo").toString());

            QString deviceId = devItem.value("deviceId").toString();

            PhaseDevice * device = new PhaseDevice(this);
            deviceList.append(device);

            ConstCache::getInstance().deviceMap.insert(deviceId, device);

            device->setComName(devItem.value("linkComName").toString());
            device->setBaudRate(SettingConfig::getInstance().BAUD_RATE);
            device->setDevCode(devItem.value("deviceNo").toString());
            device->setDeviceId(deviceId);

            connect(device, &PhaseDevice::sendDataToDraw, this, &PhaseWindow::drawPhaseDataOnPage);
            connect(device, &PhaseDevice::sendAllenToDraw, this, &PhaseWindow::drawPhaseAllenOnPage);

            this->getChannelList(deviceId);
        }
        // 5. 设置下拉框的样式
        QStandardItemModel * model = qobject_cast<QStandardItemModel*>(ui->devSelect->model());
        for (int i = 0; i < model->rowCount(); ++i)
        {
            QStandardItem * item = model->item(i);
            item->setSizeHint({ 0, 30 });
        }
    }
}

void PhaseWindow::getChannelList(QString deviceId)
{
    // 查询计数器的通道
    QJsonObject response = httpReq->getPhaseChannelList(deviceId);
    if (response.value("code").toInt() == 200)
    {
        // 将通道绘制在界面上
        QJsonArray channelArray = response.value("data").toArray();
        for (int i = 0; i < channelArray.size(); i++)
        {
            // 接口返回的channel对象
            QJsonObject channelItem = channelArray.at(i).toObject();
            QString channelId = channelItem.value("id").toString(); // 通道ID
            int channelNo = channelItem.value("channelNo").toInt();

            // 添加到通道的集合中 key=channelId value=deviceId-channelNo
            if (channelNo > 0) {
                ConstCache::getInstance().channelMap.insert(channelId, QString("%1-%2").arg(deviceId).arg(channelNo));
            }
        }
    }
}

void PhaseWindow::on_minButt_clicked()
{
    this->hide();
}
void PhaseWindow::onTrayIconActived(QSystemTrayIcon::ActivationReason reason)
{
    switch (reason) {
    case QSystemTrayIcon::Trigger: // left click
    case QSystemTrayIcon::Context: // right click
        this->show();
        break;
    default:
        break;
    }
}
void PhaseWindow::on_startButt_clicked()
{
    int devSelected = ui->devSelect->currentIndex();
    PhaseDevice * device = deviceList.at(devSelected);
    device->startWork();
}
void PhaseWindow::on_endButt_clicked()
{
    int devSelected = ui->devSelect->currentIndex();
    PhaseDevice * device = deviceList.at(devSelected);
    device->stopWork();
}

void PhaseWindow::on_devSelect_currentIndexChanged(int index)
{
    // 清空显示的数据
    if (ui->scrollContents->children().size() < 1)
    {
        return ;
    }

    for (int i = 0; i < 16; i++)
    {
        // 获取对应的通道BOX
        QGroupBox * channelBox = (QGroupBox *)ui->scrollContents->children().at(i + 1);

        // 赋值，对应的lineEdit/label
        ((QLabel *)channelBox->children().at(1))->setText("-"); // 有效性
        ((QLabel *)channelBox->children().at(2))->setText("0000"); // 数据ID
        ((QLineEdit *)channelBox->children().at(4))->setText(""); // 测量数据值

        ((QLabel *)channelBox->children().at(7))->setText("0.00"); // tau=1 Allen
        ((QLabel *)channelBox->children().at(8))->setText(QString("(%1)").arg(0)); // tau=1 Count

        ((QLabel *)channelBox->children().at(10))->setText("0.00"); // tau=10 Allen
        ((QLabel *)channelBox->children().at(11))->setText(QString("(%1)").arg(0)); // tau=10 Count

        ((QLabel *)channelBox->children().at(13))->setText("0.00"); // tau=100 Allen
        ((QLabel *)channelBox->children().at(14))->setText(QString("(%1)").arg(0)); // tau=100 Count

        ((QLabel *)channelBox->children().at(16))->setText("0.00"); // tau=1000 Allen
        ((QLabel *)channelBox->children().at(17))->setText(QString("(%1)").arg(0)); // tau=1000 Count

        ((QLabel *)channelBox->children().at(19))->setText("0.00"); // tau=10000 Allen
        ((QLabel *)channelBox->children().at(20))->setText(QString("(%1)").arg(0)); // tau=10000 Count
    }
}

void PhaseWindow::onPhaseCommandReceived(QJsonObject command)
{
    // 缺少必须的字段deviceId 或 cmd 直接返回
    if (command.contains("deviceId") == false || command.contains("cmd") == false) {
        return;
    }

    QString deviceId = command.value("deviceId").toString();
    QString cmdType = command.value("cmd").toString();

    // deviceId不属于子系统内的比相仪 直接返回
    if (ConstCache::getInstance().deviceMap.contains(deviceId) == false) {
        return;
    }

    if (cmdType.toUpper() == "START" || cmdType.toUpper() == "STOP")
    {
        // 设备开始采集或者停止采集指令
        PhaseDevice * devicePtr = ConstCache::getInstance().deviceMap.value(deviceId);
        if (devicePtr != nullptr) {
            if (cmdType.toUpper() == "START") {
                devicePtr->startWork();
            } else if (cmdType.toUpper() == "STOP") {
                devicePtr->stopWork();
            }
        }
    } else if (cmdType.toUpper() == "CLEAR")
    {
        // 清除通道的数据 通道级指令
        QString channelId = command.value("channelId").toString();
        if (ConstCache::getInstance().channelMap.contains(channelId) == true) {
            QString channelIndex = ConstCache::getInstance().channelMap.value(channelId);
            QString channelDevId = channelIndex.split("-").at(0);
            int channelNo = ((QString) channelIndex.split("-").at(1)).toInt();

            PhaseDevice * devicePtr = ConstCache::getInstance().deviceMap.value(channelDevId);
            if (devicePtr != nullptr) {
                devicePtr->clearChannelPhaseData(channelNo);
            }
        }
    }
}

void PhaseWindow::onPhaseMaserHeartHandle()
{
    QJsonObject heartRet = httpReq->phaseMasterHeartBeat();
    if (heartRet.value("code") == 200) {
        QMutex mutex;
        mutex.lock();
        ConstCache::getInstance().latestHeartTs = QDateTime::currentDateTime().currentSecsSinceEpoch();
        mutex.unlock();
    }
}
