#include "rescueload.h"

#include <QDateTime>
#include <QDir>
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QMessageBox>

// ==================== ImsiData数据类 start =======================
QHash<QString, QString> ImsiData::operatorMap = {
    {"00", "移动"}, {"02", "移动"}, {"04", "移动"}, {"07", "移动"}, {"08", "移动"}, {"13", "移动"},
    {"01", "联通"}, {"06", "联通"}, {"09", "联通"}, {"10", "联通"},
    {"03", "电信"}, {"05", "电信"}, {"11", "电信"}, {"12", "电信"},
    {"15", "广电"}, {"20","铁通"}
};
ImsiData::ImsiData(const QJsonObject& json)
{
    if (json.contains("latitude"))
        this->latitude = json.value("latitude").toString();
    if (json.contains("longitude"))
        this->longitude = json.value("longitude").toString();
    if (json.contains("altitude"))
        this->altitude = json.value("altitude").toInt();
    if (json.contains("create_date"))
        this->createDate = json.value("create_date").toString();
    if (json.contains("rssi"))
        this->rssi = json.value("rssi").toInt();
    if (json.contains("fcn"))
        this->fcn = json.value("fcn").toString();
    if (json.contains("imsi"))
        this->imsi = json.value("imsi").toString();
    this->operatorName = getOperatorNameByImsi(this->imsi); // 第4、5位
}

ImsiData::ImsiData(const ImsiData& from)
{
    this->latitude = from.latitude;
    this->longitude = from.longitude;
    this->altitude = from.altitude;
    this->createDate = from.createDate;
    this->rssi = from.rssi;
    this->fcn = from.fcn;
    this->imsi = from.imsi;
    this->operatorName = from.operatorName;
}

QString ImsiData::getOperatorNameByImsi(QString imsi)
{
    return operatorMap.value(imsi.mid(3,2));
}


// ==================== ImsiData数据类 end =======================


// ===================== ImsiTableModel start ==================================

ImsiTableModel::ImsiTableModel(QObject *parent)
    : QAbstractTableModel(parent)
{
    // Set names to the role name hash container (QHash<int, QByteArray>)
    // model.name, model.hue, model.saturation, model.brightness
    m_roleNames[imsiRole] = "imsi";
    m_roleNames[latitudeRole] = "latitude";
    m_roleNames[longitudeRole] = "longitude";
    m_roleNames[dateRole] = "createDate";
    m_roleNames[altitudeRole] = "altitude";
    m_roleNames[rssiRole] = "rssi";
    m_roleNames[fcnRole] = "fcn";
    m_roleNames[operatorRole] = "operator";

    m_horizontalHeader =  {"IMSI", "运营商"};

    m_defaultDir = QString("./搜救信息"); // 默认目录
    // 检查并创建默认目录
    QDir dir(m_defaultDir);
    if (!dir.exists()) {
        dir.mkpath(".");
    }
}

ImsiTableModel::~ImsiTableModel()
{
    QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-ddThh-mm-ss");
    QString defaultPath = QString("%1/搜救信息%2.csv").arg(getSaveDir(), timeStr);
    saveDataListToCsv(defaultPath);
}

QVariant ImsiTableModel::headerData(int section, Qt::Orientation orientation, int role) const

{
    if(orientation == Qt::Horizontal) {    //水平表头
        if(Qt::DisplayRole == role && section < m_horizontalHeader.count()) {
            return m_horizontalHeader[section];
        }
    }
    return QAbstractItemModel::headerData(section,orientation,role);
}

int ImsiTableModel::rowCount(const QModelIndex &parent) const
{
    // For list models only the root node (an invalid parent) should return the list's size. For all
    // other (valid) parents, rowCount() should return 0 so that it does not become a tree model.
    Q_UNUSED(parent)
    return m_dataMap.count();
}

int ImsiTableModel::columnCount(const QModelIndex &parent) const
{
    Q_UNUSED(parent)
    return 2;
}


QVariant ImsiTableModel::data(const QModelIndex &index, int role) const
{
    if (!index.isValid())
        return QVariant();
    int column = index.column();
    int row = index.row();

    QString imsi = m_imsiList.at(row);
    ImsiData data = m_dataMap.value(imsi);
    switch (role) {
    case Qt::DisplayRole:
        if (column == 1) {
            return data.operatorName;
        } else if (column == 0) {
            return data.imsi;
        }
        break;

     // 对齐处理
    case Qt::TextAlignmentRole:
        return Qt::AlignCenter;
        break;
    case imsiRole:
        return data.imsi;
    case latitudeRole:
        return data.latitude;
    case longitudeRole:
        return data.longitude;
    case dateRole:
        return data.createDate;
    case altitudeRole:
        return data.altitude;
    case rssiRole:
        return data.rssi;
    case fcnRole:
        return data.fcn;
    default:
        break;
    }
    return QVariant();
}

QModelIndex ImsiTableModel::index(int row, int column, const QModelIndex &parent) const
{
    if (parent.isValid() || row < 0 || column < 0 || row >= rowCount() || column >= columnCount())
        return QModelIndex();

    // Create and return a QModelIndex for the given row and column
    return createIndex(row, column);
}

void ImsiTableModel::setDataMap(const QHash<QString, ImsiData> &dataMap)
{
    beginResetModel();
    this->m_dataMap = dataMap;
    this->m_imsiList = dataMap.keys();
    for (int i = 0; i < m_imsiList.size(); ++i) {
        m_imsiIndex.insert(m_imsiList[i], i);
    }
    endResetModel();
}

void ImsiTableModel::updateData(const ImsiData &data)
{
    QString imsi = data.imsi;
    if (m_dataMap.contains(imsi)) {
        // 更新现有数据
        m_dataMap[imsi] = data;
        int row = m_imsiIndex.value(imsi);
        emit dataChanged(index(row, 0), index(row, columnCount() - 1));
    } else {
        // 插入新数据
        beginInsertRows(QModelIndex(), m_imsiList.size(), m_imsiList.size());
        m_imsiList.append(imsi);
        m_dataMap.insert(imsi, data);
        endInsertRows();
    }
}

int ImsiTableModel::getRole(QString rolename)
{
    if (rolename == "latitude")
        return latitudeRole;
    else if (rolename == "longitude")
        return longitudeRole;
    else
        return -1;
}

QHash<int, QByteArray> ImsiTableModel::roleNames() const
{
    return m_roleNames;
}

void ImsiTableModel::saveDataListToCsv(const QString& filePath,  const QString& delimiter) {
    QFile file(filePath);
    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        qWarning("Could not open file for writing.");
        return;
    }
    QTextStream out(&file);
    QStringList row;
    row << "IMSI" << "运营商"  << "经度" << "纬度" << "海拔高度"   << "频点" << "强度" << "记录时间"; // CSV header
    out << row.join(delimiter) << "\n";
    for (const QString& imsi : m_imsiList) {
        row.clear();
        ImsiData data = m_dataMap.value(imsi);
        row << data.imsi
            << data.operatorName
            << data.longitude
            << data.latitude
            << QString::number(data.altitude)
            << data.fcn
            << QString::number(data.rssi)
            << data.createDate;
        out << row.join(delimiter) << "\n";
    }
    file.close();
}
// ======================= ImsiTableModel end=====================


// ======================= RescuLoad start===========================
RescueLoad::RescueLoad(QObject *parent)
    :QObject(parent), remoteIp("10.10.10.50"), remotePort(8056)
{
    // remoteIp = "127.0.0.1";
}

RescueLoad::~RescueLoad() {}


void RescueLoad::startCommunication()
{
    udpSocket = new QUdpSocket(this);
    connect(udpSocket, &QUdpSocket::readyRead, this, &RescueLoad::readData);
}


void RescueLoad::sendMessage(const QString &message)
{
    QByteArray datagram = message.toUtf8();
    udpSocket->writeDatagram(datagram, QHostAddress(remoteIp), remotePort);
}

void RescueLoad::sendMessage(const QByteArray &datagram)
{
    udpSocket->writeDatagram(datagram, QHostAddress(remoteIp), remotePort);
}

void RescueLoad::readData()
{
    while (udpSocket->hasPendingDatagrams()) {
        QByteArray datagram;
        datagram.resize(udpSocket->pendingDatagramSize());
        QHostAddress sender;
        quint16 senderPort;
        udpSocket->readDatagram(datagram.data(), datagram.size(), &sender, &senderPort);
        // qDebug() << "Received response from" << sender.toString() << ":" << senderPort;
        // qDebug() << "Data:" << datagram;
        handleMessage(datagram);
    }
}
void RescueLoad::handleMessage(const QByteArray &datagram) {

    QJsonParseError json_error;
    QJsonDocument jsonDoc(QJsonDocument::fromJson(datagram, &json_error));
    if(json_error.error != QJsonParseError::NoError || !jsonDoc.isObject()){
        qDebug() << "json error!";
        return;
    }

    QJsonObject baseObj = jsonDoc.object();

    QJsonValue vType = baseObj.value("type");
    QJsonValue vMsg = baseObj.value("msg");
    // if (!vType.isDouble() || !vMsg.isString()) return;

    int type = vType.toInt();
    QString msg = vMsg.toString();
    // if ("success" != msg) return;

    switch (type) {
    case 1: // 4G心跳包
        // todo
        sendMessage(QString("{\"cmd\": \"heartbeat\"}")); // 定时回心跳,或者单独开定时器
        break;
    case 2: // 5G心跳包
        sendMessage(QString("{\"cmd\": \"heartbeat\"}"));
        break;
    case 3:{ // IMSI数据
        QJsonArray array = baseObj.value("data").toArray();

        for (int i = 0; i < array.size(); i++){
            QJsonObject json = array.at(i).toObject();
            ImsiData data(json);
            // ImsiData data;
            emit dataUpdate(data);
        }
        break;
    }
    default:
        break;
    }
}

void RescueLoad::syncTime()
{
    QString timeStr = QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss");
    QJsonObject timeObj;
    timeObj.insert("datetime", timeStr);

    QJsonObject sendObj;
    sendObj.insert("cmd", "syncTime");
    sendObj.insert("params", timeObj);

    sendMessage(QJsonDocument(sendObj).toJson(QJsonDocument::Compact));
}

/**
 * @brief RescueLoad::sendNameList 设置黑白名单
 * @param action: 'reject'/'block'/'reject2lte'/'release2lte', #对其他imsi动作,
 * @param type: 'ADD'/'SUB'/'SAVE'  #名单配置模式,ADD:增加名单,SUB:删除名单,SAVE:名单替换
 * @param wnamelist: IMSI字符串列表
 * @param bnamelist: IMSI字符串列表
 */
void RescueLoad::sendNameList(const QString action, const QString type, const QList<QString> &wnamelist, const QList<QString> &bnamelist)
{
    QJsonObject paramsObj;
    paramsObj.insert("action", action);
    paramsObj.insert("type", type);
    paramsObj.insert("wnamelist", QJsonArray::fromStringList(wnamelist));
    paramsObj.insert("bnamelist", QJsonArray::fromStringList(bnamelist));

    QJsonObject sendObj;
    sendObj.insert("cmd", "msg_set_namelist");
    sendObj.insert("params", paramsObj);

    sendMessage(QJsonDocument(sendObj).toJson(QJsonDocument::Compact));
}

// ============================ RescueLoad end=================================