#include "FrequencyTuning.h"
#include <iostream>
#include <QDateTime>
#include "DeviceHubWindow.h"

FrequencyTuning::FrequencyTuning(QObject *parent) : DeviceBase(parent)
{
    this->devType = "03";
    connect(&this->serialUtil, &QSerialPortUtil::dataRecieved,
            this, &FrequencyTuning::dataReceivedHandler);

    connect(this, &FrequencyTuning::sendDataToDraw,
            ((DeviceHubWindow *)this->parent())->freqTunForm, &FrequencyTuningForm::drawDeviceFrameOnForm);
    connect(this, &FrequencyTuning::sendCommandToDisplay,
            ((DeviceHubWindow *)this->parent())->freqTunForm, &FrequencyTuningForm::displayDeviceCommandOnForm);

    connect(((DeviceHubWindow *)this->parent())->kafkaConsumer, &QKafkaConsumer::messageRecieved,
            this, &FrequencyTuning::commandReceivedHandler);

    kafkaProducer.setBrokers(SettingConfig::getInstance().KAFKA_BROKERS);
    kafkaProducer.setTopic(SettingConfig::getInstance().KAFKA_DATA_TOPIC);
    kafkaProducer.createProducer();

    this->protocol = DeviceProtocolBase::deviceProtocolFactory(devType);
}

FrequencyTuning::~FrequencyTuning()
{
    disconnect(&this->serialUtil, &QSerialPortUtil::dataRecieved,
               this, &FrequencyTuning::dataReceivedHandler);
}

void FrequencyTuning::mockReceivData()
{
    QByteArray buffer;

    // frequency tuning
//    buffer.append("$GLN,0,192.168.1.126,255.255.255.0,192.168.1.1,255.255.255.255,3000,2000,2001*71").append("\r\n");
//    buffer.append("$GLF,0,0,0,0,00000,0,0,0,0,0,0,0,0,0,0,0,1900,2355,0,0,0,0,0,1,1,1*4C").append("\r\n");
//    buffer.append("$GLP,0,1000,0,100,20000*45").append("\r\n");
    buffer.append("000$1C2BM1304-3021010071204312*$572BM1304-30210100713 -2.52E-10 +3.02E-14 -000000002000 00000");
    this->dataReceivedHandler(buffer);

    QTimer::singleShot(20, this, [=](){
        QByteArray buffer;
        buffer.append("8000 +0000000027.6007BAF*");
        this->dataReceivedHandler(buffer);
    });
}

void FrequencyTuning::dataReceivedHandler(QByteArray data)
{
    this->dataBuff.append(data);

    QDateTime now = QDateTime::currentDateTime();
    // 0. 输出到日志文件中
    QString date = now.toString("yyyy-MM-dd");

    // 1. 原始字节数组数据
    QString filename = "serial_" + devCode + ".log";
    QString content = now.toString("yyyy-MM-dd HH:mm:ss.zzz") + " [recv] " + data + "\r\n[buffer]" + dataBuff.toHex();
    QLogUtil::writeRawDataLogByDate(date, filename, content);

    int start = dataBuff.indexOf("$");
    if (start < 0)
    {
        return;
    }
    dataBuff = dataBuff.right(dataBuff.size() - start);

    int end = dataBuff.lastIndexOf("*");
    if (end < 0) {
        return;
    }
    QByteArray rawFrame = dataBuff.left(end + 1);
    dataBuff = dataBuff.right(dataBuff.size() - end - 1);

    QList<QByteArray> frameList = protocol->extractFrameList(rawFrame);
//    std::cout << QString("[%1]: ").arg(frameList.size()).toStdString() << dataBuff.toStdString() << std::endl;
    if (frameList.size() > 0)
    {
//        this->dataBuff.clear();
        frameParse(frameList);
    }
}

void FrequencyTuning::frameParse(QList<QByteArray> frameList)
{
    for (int i = 0; i < frameList.size(); i++)
    {
        QByteArray frameByte = frameList.at(i);

        int frameType = protocol->checkFrame(frameByte);
        DeviceFrameBaseDto * frameDto = protocol->frameFactory(frameType);
        if (frameDto != nullptr)
        {
            // ★解析成数据对象
            bool parse = protocol->parseDeviceFrameData(frameByte, frameDto, frameType);

            // 解析成功
            if (parse == true)
            {
                QDateTime now = QDateTime::currentDateTime();
                frameDto->timestamp = now.toString("yyyy-MM-dd HH:mm:ss.zzz");
                frameDto->milisecond = now.toMSecsSinceEpoch();
                frameDto->rawFrame = frameByte;

                frameDto->devCode = devCode;

                if (frameType == FrequencyTuningProtocolTX::FrequencyTuningProtocolTX::STATUS_FRAME ||
                        frameType == FrequencyTuningProtocolTX::FREQUENCY_TUNING_FRAME_TYPE::LOCK_FRAME)
                {
                    this->afterFrameParse(frameDto);
                }

                if (frameType == FrequencyTuningProtocolTX::FrequencyTuningProtocolTX::CMDREP_FRAME)
                {
                    frameDto->rawCommand = rawCommandBytes;
                    frameDto->commandId = commandId;
                    this->afterCommandReply(frameDto);
                }
            }

            // 在此处释放内存，不影响后续显示
            // 不在此处释放内存则会导致内存持续增加
            // 具体原因不明
            delete frameDto;
        }
    }
}
void FrequencyTuning::afterFrameParse(DeviceFrameBaseDto * frameDto)
{
//    std::cout << "frame type: " << typeid(* frameDto).name() << std::endl;
//    std::cout << frameDto->rawFrame.toStdString() << std::endl;

    // 0. 输出到日志文件中
    QString date = frameDto->timestamp.mid(0, 10);

    // 1. 原始字节数组数据
    QString filename = "raw_" + devCode + ".log";
    QString content = frameDto->timestamp + " [recv] " + frameDto->rawFrame.left(frameDto->rawFrame.size());
    QLogUtil::writeRawDataLogByDate(date, filename, content);

    // 2. 解析后的json数据
    QString frameFilename = "frame_" + devCode + ".log";
    QString frameContent = frameDto->timestamp + " [recv] " + QJsonDocument(frameDto->toJSON()).toJson(QJsonDocument::Compact);
    QLogUtil::writeChannelDataLogByDate(date, frameFilename, frameContent);

    // 3. 输出到中间件，执行后续处理过程
    if (SettingConfig::getInstance().NEED_KAFKA == 1)
    {
        QJsonObject jsonObj = frameDto->toJSON();
        jsonObj.insert("clientId", SettingConfig::getInstance().CLIENT_ID);
        jsonObj.insert("deviceId", deviceId);
        kafkaProducer.produceMessage(QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact)));
    }

    // 4. 在界面上简单显示相差数据结果
    emit this->sendDataToDraw(frameDto);
}

void FrequencyTuning::afterCommandReply(DeviceFrameBaseDto * frameDto)
{
    // 0. 输出到日志文件中
    QString date = frameDto->timestamp.mid(0, 10);

    // 1. 原始字节数组数据
    QString filename = "raw_" + devCode + ".log";
    QString content = frameDto->timestamp + " [recv] " + frameDto->rawFrame.left(frameDto->rawFrame.size());
    QLogUtil::writeRawDataLogByDate(date, filename, content);

    // 2. 解析后的json数据
    QString frameFilename = "frame_" + devCode + ".log";
    QString frameContent = frameDto->timestamp + " [reply] " + QJsonDocument(frameDto->toJSON()).toJson(QJsonDocument::Compact);
    QLogUtil::writeChannelDataLogByDate(date, frameFilename, frameContent);

    // 3. 输出到中间件，执行后续处理过程
    if (SettingConfig::getInstance().NEED_KAFKA == 1)
    {
        QJsonObject jsonObj = frameDto->toJSON();
        kafkaProducer.produceMessage(SettingConfig::getInstance().KAFKA_CMDCB_TOPIC, QString(QJsonDocument(jsonObj).toJson(QJsonDocument::Compact)));
    }
}

void FrequencyTuning::sendDataToSerial(QByteArray data)
{
    CommandReplyDto replyDto;
    replyDto.devCode = devCode;
    replyDto.commandId = commandId;
    replyDto.rawCommand = rawCommandBytes;

//    data.append(FRAME_TAIL);
    if (SettingConfig::getInstance().WORK_MODE == "real")
    {
        if (serialUtil.isOpen() == true)
        {
            this->serialUtil.sendData(data);
        } else
        {
            replyDto.cmdStatus = 0;
            replyDto.remarks = "serialport not avilable";

            // 3. 输出到中间件，执行后续处理过程
            if (SettingConfig::getInstance().NEED_KAFKA == 1)
            {
                kafkaProducer.produceMessage(SettingConfig::getInstance().KAFKA_CMDCB_TOPIC,
                                             QString(QJsonDocument(replyDto.toJSON()).toJson(QJsonDocument::Compact)));
            }
            return;
        }
    }

    // 记录日志
    // 0. 输出到日志文件中
    QDateTime now = QDateTime::currentDateTime();
    QString date = now.toString("yyyy-MM-dd");

    // 1. 原始字节数组数据
    QString filename = "rawCmd_" + devCode + ".log";
    QString content = now.toString("yyyy-MM-dd HH:mm:ss.zzz") + " [send] " + data.left(data.size());
    QLogUtil::writeRawDataLogByDate(date, filename, content);

    std::cout << content.toStdString() << std::endl;
}

void FrequencyTuning::commandReceivedHandler(QJsonObject command)
{
    if (command.contains("deviceType") == false || command.value("deviceType").toString() != "03")
    {
        return;
    }

    if (command.contains("deviceId") == false || command.value("deviceId").toString() != deviceId)
    {
        return;
    }

    // 记录日志
    // 0. 输出到日志文件中
    QDateTime now = QDateTime::currentDateTime();
    QString date = now.toString("yyyy-MM-dd");

    // 1. 原始字节数组数据
    QString filename = "cmd_" + devCode + ".log";
    QString content = now.toString("yyyy-MM-dd HH:mm:ss.zzz") + " [recv] " + command.find("cmdStr")->toString();
    QLogUtil::writeChannelDataLogByDate(date, filename, content);

    QByteArray commandBytes = protocol->generateSettingCommand(devCode, command.value("command").toString(), command.value("params").toString());
    command.insert("rawCommand", QString::fromUtf8(commandBytes));
    this->commandId = command.value("commandId").toString();
    this->rawCommandBytes = commandBytes;
    this->sendDataToSerial(commandBytes);

    // display on page
    emit sendCommandToDisplay(command);
}
