#include "RamdomForestCalculate.h"
#include <QCoreApplication>
#include "spdlog/spdlog.h"
#include <QFileInfo>

int pickPriorityValue(double xpred, double ypred, double zpred)
{
    // 四舍五入
    int x = qRound(xpred);
    int y = qRound(ypred);
    int z = qRound(zpred);

    // 优先检查 1 → 2 → 3
    if (x == 1 || y == 1 || z == 1) return 1;
    if (x == 2 || y == 2 || z == 2) return 2;
    if (x == 3 || y == 3 || z == 3) return 3;

    return 0;   // 都没有
}

void CreatTable()
{
    QString dbPath = QString("/home/pi/SigerTMS/stream/SAC/%1.db")
                         .arg("RamdomForestFeatureValue");

    // 判断数据库文件是否存在
    QFileInfo fi(dbPath);
    if (!fi.exists()) {
        qDebug() << "Database not exists. Creating...";

        // ---- 短连接：打开 -> 执行建表语句 -> 关闭 ----
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", "InitConnection");
        db.setDatabaseName(dbPath);

        if (!db.open()) {
            qDebug() << "Create DB failed:" << db.lastError().text();
            return;
        }

        QString createTable = QString(
            "CREATE TABLE IF NOT EXISTS RamdomForestFeatureValue("
            "id INTEGER PRIMARY KEY AUTOINCREMENT, "
            "StartTime TEXT NOT NULL, "
            "EndTime TEXT NOT NULL, "
            "target TEXT NOT NULL, "
            "Label INTEGER NOT NULL, "
            "x TEXT NOT NULL, "
            "y TEXT NOT NULL, "
            "z TEXT NOT NULL, "
            "created_at TEXT DEFAULT CURRENT_TIMESTAMP)"
        );

        QSqlQuery query(db);
        if (!query.exec(createTable)) {
            qDebug() << "Create table error:" << query.lastError().text();
        }

        db.close();
        QSqlDatabase::removeDatabase("InitConnection");

        qDebug() << "Database and table created.";
    }
}

bool execShortConn(QString sql, const QString &dbFile)
{
    // 生成唯一连接名
    QString conn = QString("short_%1_%2")
                       .arg((qulonglong)QThread::currentThreadId())
                       .arg(QDateTime::currentMSecsSinceEpoch());

    bool ok = false;

    {
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", conn);
        db.setDatabaseName(dbFile);

        if (!db.open()) {
            qWarning() << "open failed:" << db.lastError();
            QSqlDatabase::removeDatabase(conn);
            return false;
        }

        // WAL & busy_timeout 可提升稳定性
        QSqlQuery prag(db);
        prag.exec("PRAGMA journal_mode=WAL;");
        prag.exec("PRAGMA synchronous=NORMAL;");
        prag.exec("PRAGMA busy_timeout=3000;");

        QSqlQuery query(db);
        ok = query.exec(sql);
        if (!ok) {
            qWarning() << "SQL ERROR:" << query.lastError();
        }

        db.close();
    }

    QSqlDatabase::removeDatabase(conn);
    return ok;
}

//发送给流式的消息
RamdomForestCalculate::RamdomForestCalculate(QObject *parent)
{
    QString a = "算法模块开始运行";
    SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"{}",a.toStdString());

    qRegisterMetaType<Dc_SacData>("Dc_SacData");

    m_tcpServerManager = new TcpServerManager();  // 实例化
    m_tcpServerManager->startServer(2026);

    //dbFunc =  new DBFunc();  // 实例化
    //dbFunc->startDBThread("RamdomForestFeatureValue");

    //1.初始化分类器
    Classifier = new RandomForestClassifier(10, 4);


    //2.创建数据库表
    CreatTable();


    //3.训练初始模型
    QString dbPath = QString("/home/pi/SigerTMS/stream/SAC/%1.db").arg("RamdomForestFeatureValue");
    QList<SACRecord> record = queryRecordsByLabel(dbPath,0);

    if(record.size() != 0)
    {
        IfHaveModel = true;
        std::vector<std::vector<float>> FearValues;
        std::vector<int> TypeValues;
        DealRecord(record,FearValues,TypeValues);
        Classifier->train(FearValues, TypeValues, 0.2f, 100);
    }

    //GLS Test
//    StreamInfo info(1,"C$14$1$1$1$202$0","1764581206660-0","0");
//    SendStreamAlarminfo(info);


    //连接信号和槽函数
    QObject::connect(m_tcpServerManager, &TcpServerManager::getdc_sacdata,
                     [=](const Dc_SacData &sac_data) {

        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"收到 dc_sacdata 信号");
        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"Source:{}",sac_data.source.toStdString());
        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"SacFile:{}",sac_data.sacFile.toStdString());
        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"Target:{}",sac_data.target.toStdString());

        Save_SACDATA(sac_data);  // 现在可以识别了
    });

    //连接TMS信号和槽函数
    QObject::connect(m_tcpServerManager, &TcpServerManager::TMSTrain,
                     [=]() {
        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"收到 TMS 信号");
        IfHaveModel = true;
        Retrain();
        //重新训练
    });




}

QString RamdomForestCalculate::QueryPowerData(const StreamInfo &alarmInfo)
{
    QString dbPath = QString("/home/pi/SigerTMS/stream/slice/slice_%1.db").arg(alarmInfo.target);

    QString result = "";

    QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE");
    db.setDatabaseName(dbPath);

    if (!db.open()) {
        qDebug() << "无法打开数据库:" << db.lastError().text();
        return result;
    }

    QSqlQuery query;
    QString sql = QString("SELECT data FROM slice WHERE start_cursor = '%1'").arg(alarmInfo.startIds);

    if (query.exec(sql) && query.next()) {
        result = query.value(0).toString();
    }

    db.close();
    return result;
}

void RamdomForestCalculate::SendStreamAlarminfo(const StreamInfo &alarmInfo)
{
    QString ip("127.0.0.1");
    TcpClient tcp_client(ip, 5999);
    QJsonObject json;
    json["source"] = STREAM_MESSAGE;
    json["typealarm"] = QString::number(alarmInfo.alarmtype);
    json["target"] = alarmInfo.target;
    json["startIds"] = alarmInfo.startIds;
    json["endIds"] = alarmInfo.endIds;

    tcp_client.sendData(QString(QJsonDocument(json).toJson(QJsonDocument::Compact)).toStdString().c_str());
    SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"发送流式报警信息成功");

    // 创建短连接 TcpClient
//    TcpClient* client = new TcpClient();

//    // 构造消息
//    QJsonObject message;
//    message["source"] = STREAM_MESSAGE;
//    message["typealarm"] = QString::number(alarmInfo.alarmtype);
//    message["target"] = alarmInfo.target;
//    message["startIds"] = alarmInfo.startIds;
//    message["endIds"] = alarmInfo.endIds;

//    // 连接成功后发送消息
//    QObject::connect(client, &TcpClient::connected, [client, message]() {
//        qDebug() << "=== 连接成功，开始发送报警消息 ===";

//        client->sendMessage(message);

//        // 延迟关闭，确保消息发送完成
//        QTimer::singleShot(200, client, [client]() {
//            //client->disconnectFromServer();
//            client->deleteLater();
//        });

//        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),
//                            "发送流式报警信息成功");
//    });

//    // 连接错误也自动释放
//    QObject::connect(client, &TcpClient::errorOccurred, [client](const QString &err) {
//        qWarning() << "TcpClient错误:" << err;
//        client->deleteLater();
//    });

//    // 发起连接
//    client->connectToServer("127.0.0.1", STREAM_PORT);
}


//void RamdomForestCalculate::SendStreamAlarminfo(const StreamInfo &alarmInfo)
//{
//    TcpClient* client = new TcpClient();

//    // 统一的清理函数
//    auto cleanup = [client]() {
//        static bool cleaned = false;  // 静态变量确保只清理一次收到 TMS 信号
//        if (!cleaned) {
//            cleaned = true;
//            //qDebug() << "清理客户端资源";
//            client->disconnectFromServer();
//            QTimer::singleShot(0, client, &QObject::deleteLater);  // 延迟删除确保安全
//        }
//    };

//    // 连接所有信号到统一的清理函数
//    QObject::connect(client, &TcpClient::connected, [client, alarmInfo, cleanup]() {
//        qDebug() << "=== 连接成功，开始发送报警消息 ===";

//        QJsonObject message;
//        message["source"] = STREAM_MESSAGE;
//        message["typealarm"] = QString::number(alarmInfo.alarmtype);
//        message["target"] = alarmInfo.target;
//        message["startIds"] = alarmInfo.startIds;
//        message["endIds"] = alarmInfo.endIds;
//        //message["power"] = alarmInfo.endIds;

//        client->sendMessage(message);
//        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"发送给流式告警信息成功");

//        // 发送完成后立即开始清理
//        cleanup();
//    });

//    QObject::connect(client, &TcpClient::disconnected, cleanup);
//    QObject::connect(client, &TcpClient::messageReceived, cleanup);
//    QObject::connect(client, &TcpClient::errorOccurred, cleanup);

//    // 设置连接超时（5秒）
//    QTimer::singleShot(5000, client, cleanup);

//    // 连接到服务器
//    qDebug() << "正在连接到服务器...";
//    client->connectToServer("127.0.0.1", STREAM_PORT);
//}

QList<SACRecord> RamdomForestCalculate::queryRecordsByLabel(const QString &dbFileName, int targetLabel)
{
    QList<SACRecord> records;

    // ==== 1. 建立唯一连接名 ====
    QString conn = QString("rf_query_%1_%2")
                       .arg((qulonglong)QThread::currentThreadId())
                       .arg(QDateTime::currentMSecsSinceEpoch());

    {
        QSqlDatabase db = QSqlDatabase::addDatabase("QSQLITE", conn);
        db.setDatabaseName(dbFileName);

        if (!db.open()) {
            qDebug() << "Database open failed:" << db.lastError().text();
            QSqlDatabase::removeDatabase(conn);
            return records;
        }

        // PRAGMA（可选但推荐）
        QSqlQuery prag(db);
        prag.exec("PRAGMA journal_mode=WAL;");
        prag.exec("PRAGMA synchronous=NORMAL;");
        prag.exec("PRAGMA busy_timeout=3000;");

        // ==== 2. 执行查询 ====
        QString sql = QString("SELECT * FROM RamdomForestFeatureValue WHERE Label != %1")
                          .arg(targetLabel);

        QSqlQuery query(db);
        if (!query.exec(sql)) {
            qDebug() << "Query failed:" << query.lastError().text();
            db.close();
            QSqlDatabase::removeDatabase(conn);
            return records;
        }

        // ==== 3. 遍历结果 ====
        while (query.next()) {
            SACRecord record;
            record.startTime = query.value("StartTime").toString();
            record.endTime = query.value("EndTime").toString();
            record.target = query.value("target").toString();
            record.label = query.value("Label").toInt();
            record.x = query.value("x").toString();
            record.y = query.value("y").toString();
            record.z = query.value("z").toString();

            records.append(record);
        }

        db.close();
    }

    // ==== 4. 删除连接（必须先关闭再删除） ====
    QSqlDatabase::removeDatabase(conn);

    return records;
}


int RamdomForestCalculate::Save_SACDATA(const Dc_SacData &sacdata)
{
    std::array<std::vector<float>, 3> raw;

    QString FilePath = QString("/home/pi/SigerTMS/stream/SAC/%1").arg(sacdata.sacFile);

    //step1: 读取二进制原始文件
    VibrationDataReader reader;
    if (reader.readFileRaw(FilePath)) {
        reader.printDataInfo();
    }

    raw = reader.convertToRawFormat();
    //parseSACData("斯凯孚换刀周期1.dat", raw[0], raw[1], raw[2]);
    QString x;
    QString y;
    QString z;

    FeatureExtractor extractor;
    SignalFeatures fea[3];
    for (int i=0; i<3; ++i)
        fea[i] = extractor.extract_features(raw[i]);

    for (int i=0; i<3; ++i)
    {
        fea[i].print();
        if(i == 0)
        {
            fea[i].fill(x);
        }
        else if(i == 1)
        {
            fea[i].fill(y);
        }
        else if(i == 2)
        {
            fea[i].fill(z);
        }
    }
    //step2: 预测报警
    //std::string data;
    qDebug()<<"x "<<x;

    if(IfHaveModel)
    {
        //X轴预测
        std::vector<float> xtest_sample;
        //用逗号分割
        QStringList xlist = x.split(',');

        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"xlist: {}",xlist.size());

        //转成 float 并存到 vector
        for (const QString &s : xlist) {
            bool ok = false;
            float f = s.toFloat(&ok);
            if (ok) {
                xtest_sample.push_back(f);
            } else {
                std::cerr << "转换失败: " << s.toStdString() << std::endl;
            }
        }

        double xpred = Classifier->predict(xtest_sample);
        //cout << "测试样本预测类别: " << pred << endl;
        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"x轴测试样本预测类别: {}",xpred);

        //Y轴预测
        std::vector<float> ytest_sample;
        //用逗号分割
        QStringList ylist = y.split(',');

        //转成 float 并存到 vector
        for (const QString &s : ylist) {
            bool ok = false;
            float f = s.toFloat(&ok);
            if (ok) {
                ytest_sample.push_back(f);
            } else {
                std::cerr << "转换失败: " << s.toStdString() << std::endl;
            }
        }
        double ypred = Classifier->predict(ytest_sample);
        //cout << "测试样本预测类别: " << pred << endl;
        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"y轴测试样本预测类别: {}",ypred);

        //Z轴预测
        std::vector<float> ztest_sample;
        //用逗号分割
        QStringList zlist = z.split(',');

        //转成 float 并存到 vector
        for (const QString &s : zlist) {
            bool ok = false;
            float f = s.toFloat(&ok);
            if (ok) {
                ztest_sample.push_back(f);
            } else {
                std::cerr << "转换失败: " << s.toStdString() << std::endl;
            }
        }
        double zpred = Classifier->predict(ztest_sample);
        //cout << "测试样本预测类别: " << pred << endl;
        SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"z轴测试样本预测类别: {}",zpred);

        int predRes  = pickPriorityValue(xpred,ypred,zpred);


        StreamInfo info(predRes,sacdata.target,sacdata.startIds,sacdata.endIds);
        SendStreamAlarminfo(info);
    }

    //step3: 存入数据库
    std::string data = QString(
        "INSERT INTO RamdomForestFeatureValue (StartTime, EndTime, target, Label, x, y, z) "
        "VALUES ('%1', '%2', '%3', %4, '%5', '%6', '%7')"
    )
    .arg(sacdata.startIds) //开始时间
    .arg(sacdata.endIds) // 结束时间
    .arg(sacdata.target)  // 设备编号
    .arg(0)  // Label: 1,2,3 循环
    .arg(x)   // x 特征值
    .arg(y)   // y 特征值
    .arg(z)   // z 特征值
    .toStdString();

    QString dbPath = QString("/home/pi/SigerTMS/stream/SAC/%1.db")
                         .arg("RamdomForestFeatureValue");

    QString sql = QString::fromStdString(data);
    bool ok = execShortConn(sql, dbPath);

    if (!ok) {
        qWarning() << "Insert failed!";
    }

    //dbFunc->addDataToQueue(data);

    //step4: 删除二进制文件
    //QFile::remove(FilePath);

    return 0;
}

int RamdomForestCalculate::judge_alarm()
{

}

void RamdomForestCalculate::DealRecord(const QList<SACRecord> &record, std::vector<std::vector<float> > &result1, std::vector<int> &result2)
{
    std::vector<float> tmpresult;

    foreach (auto tmp, record) {
        //1.解析振动量
        QStringList list = tmp.x.split(',');
        tmpresult.clear();
        for (const QString& item : list) {
            bool ok;
            float value = item.toFloat(&ok);
            if (ok) {
                tmpresult.push_back(value);
            }
        }
        result1.push_back(tmpresult);
        result2.push_back(tmp.label);

        list.clear();
        tmpresult.clear();
        list = tmp.y.split(',');
        for (const QString& item : list) {
            bool ok;
            float value = item.toFloat(&ok);
            if (ok) {
                tmpresult.push_back(value);
            }
        }
        result1.push_back(tmpresult);
        result2.push_back(tmp.label);

        list.clear();
        tmpresult.clear();
        list = tmp.z.split(',');
        for (const QString& item : list) {
            bool ok;
            float value = item.toFloat(&ok);
            if (ok) {
                tmpresult.push_back(value);
            }
        }
        result1.push_back(tmpresult);
        //2.解析特征值
        result2.push_back(tmp.label);

    }
    return;
}

void RamdomForestCalculate::Retrain()
{
    QString dbPath = QString("/home/pi/SigerTMS/stream/SAC/%1.db").arg("RamdomForestFeatureValue");
    QList<SACRecord> record = queryRecordsByLabel(dbPath,0);

    std::vector<std::vector<float>> FearValues;
    std::vector<int> TypeValues;
    DealRecord(record,FearValues,TypeValues);
    Classifier->train(FearValues, TypeValues, 0.2f, 100);

    SPDLOG_LOGGER_DEBUG(spdlog::get("logger"),"Begin Train RamdomForestModel");

}
