#include "appevent.h"
#include "qdir.h"
#include "qglobal.h"
#include "qjsonobject.h"
#include "qobject.h"

#include <QByteArray>
#include <QCryptographicHash>
#include <QDateTime>
#include <QFile>
#include <QGuiApplication>
#include <QJsonDocument>
#include <QPainter>
#include <QPixmap>
#include <QScreen>

#include "thardware/thardware.h"

static AppEvent *g_instance = nullptr;

static QString computeMD5(const QString &input)
{
    // Convert the input string to a QByteArray
    QByteArray byteArray = input.toUtf8();

    // Compute the MD5 hash using QCryptographicHash
    QByteArray hash = QCryptographicHash::hash(byteArray, QCryptographicHash::Md5);

    // Convert the QByteArray hash to a hexadecimal string
    QString hexHash = hash.toHex();

    return hexHash;
}

class AppEventPrivate
{
public:
    AppEventPrivate()
    {
        token = "";
        accessExpire = 0;
        machineCode = "";
        locale = QLocale::system().name();
        enableRefreshToken = true;
    }

    QString token;
    qint64 accessExpire;

    QJsonObject jsonConfig;

    QString machineCode;

    QString locale;

    bool enableRefreshToken;

    QStringList roles;
    QString userId;
    QString userName;
};

AppEvent::AppEvent(QObject *parent)
    : QObject{parent}
    , d(new AppEventPrivate)
{
    const std::string code = TC::THardWare::machineCode();
    d->machineCode = computeMD5(QString::fromStdString(code));

    // 考题存放路径
    d->jsonConfig.insert("serverIP", "127.0.0.1");
    d->jsonConfig.insert("serverPort", "8080");
    d->jsonConfig.insert("webSocketIP", "127.0.0.1");
    d->jsonConfig.insert("webSocketPort", "8081");
}

AppEvent::~AppEvent()
{
    delete d;
}

AppEvent *AppEvent::instance()
{
    if (!g_instance) {
        g_instance = new AppEvent();
    }
    return g_instance;
}

qint64 AppEvent::time()
{
    QDateTime currentDateTime = QDateTime::currentDateTime();
    qint64 timestamp = currentDateTime.toSecsSinceEpoch();
    timestamp /= 1000; // 转换为10位时间戳
    return timestamp;
}

QString AppEvent::formatElapsedTime(qint64 ms)
{
    // 构建QTime对象
    QTime time(0, 0, 0);
    time = time.addMSecs(ms);
    // 格式化成时:分:秒:毫秒格式
    return time.toString("hh:mm:ss");
}

void AppEvent::captureDesktop(QIODevice *device, const char *format, int quality)
{
    QList<QScreen *> screens = QGuiApplication::screens();
    if (screens.isEmpty()) {
        qWarning("No screens found.");
        return;
    }

    // 计算整个桌面的大小
    QRect fullDesktopRect;
    for (QScreen *screen : screens) {
        fullDesktopRect = fullDesktopRect.united(screen->geometry());
    }

    // 创建一个空白的 QPixmap，大小为整个桌面的大小
    QPixmap fullDesktop(fullDesktopRect.size());
    fullDesktop.fill(Qt::transparent);

    // 使用 QPainter 将每个屏幕的内容绘制到 fullDesktop 上
    QPainter painter(&fullDesktop);
    for (QScreen *screen : screens) {
        // 计算当前屏幕在 fullDesktop 中的位置
        QPoint screenPos = screen->geometry().topLeft() - fullDesktopRect.topLeft();
        painter.drawPixmap(screenPos, screen->grabWindow(0));
    }
    painter.end();

    fullDesktop.save(device, format, quality);
}

void AppEvent::captureDesktop(const QString &path)
{
    QList<QScreen *> screens = QGuiApplication::screens();
    if (screens.isEmpty()) {
        qWarning("No screens found.");
        return;
    }

    // 计算整个桌面的大小
    QRect fullDesktopRect;
    for (QScreen *screen : screens) {
        fullDesktopRect = fullDesktopRect.united(screen->geometry());
    }

    // 创建一个空白的 QPixmap，大小为整个桌面的大小
    QPixmap fullDesktop(fullDesktopRect.size());
    fullDesktop.fill(Qt::transparent);

    // 使用 QPainter 将每个屏幕的内容绘制到 fullDesktop 上
    QPainter painter(&fullDesktop);
    for (QScreen *screen : screens) {
        // 计算当前屏幕在 fullDesktop 中的位置
        QPoint screenPos = screen->geometry().topLeft() - fullDesktopRect.topLeft();
        painter.drawPixmap(screenPos, screen->grabWindow(0));
    }
    painter.end();

    // 保存截图到文件（可选）
    QString fileName = "/desktop_screenshot_"
                       + QDateTime::currentDateTime().toString("yyyy-MM-dd-hh-mm-ss") + ".png";

    fullDesktop.save(path + fileName, "PNG");
}

void AppEvent::saveTimeFile(qint64 elapsed, const QString &path)
{
    QFile file(path + "/time.txt");

    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QTextStream stream(&file);
        QString time = formatElapsedTime(elapsed); // Assuming formatElapsedTime is defined somewhere
        stream << "time: " << time << Qt::endl;
        stream << "elapsed(ns): " << elapsed << Qt::endl;
        file.close();
    }
}

QString AppEvent::machineCode() const
{
    return d->machineCode;
}
QString AppEvent::locale() const
{
    return d->locale;
}

void AppEvent::setLocale(const QString &locale)
{
    if (d->locale != locale) {
        d->locale = locale;
    }
}
bool AppEvent::isLogin()
{
    return !d->token.isEmpty();
}

void AppEvent::setJwtToken(const QString &token)
{
    d->token = token;
}

QString AppEvent::jwtToken() const
{
    return d->token;
}

bool AppEvent::isRefreshToken() const
{
    if (time() > d->accessExpire && !d->token.isEmpty()) {
        return true;
    }
    return false;
}

void AppEvent::setRefreshTime(qint64 time) const
{
    d->accessExpire = time;
}

bool AppEvent::isEnableRefreshToken() const
{
    return d->enableRefreshToken;
}

void AppEvent::setEnableRefreshToken(bool enable)
{
    if (d->enableRefreshToken != enable) {
        d->enableRefreshToken = enable;
    }
}

void AppEvent::setUserId(const QString &id)
{
    d->userId = id;
}

QString AppEvent::userId() const
{
    return d->userId;
}

void AppEvent::setUserName(const QString &name)
{
    d->userName = name;
}
QString AppEvent::userName() const
{
    return d->userName;
}

void AppEvent::setRoles(const QStringList &roles)
{
    d->roles = roles;
}

QStringList AppEvent::roles() const
{
    return d->roles;
}

bool AppEvent::hasRole(const QString &role)
{
    return d->roles.contains(role);
}

bool AppEvent::setConfigValue(const QString &key, const QVariant &value)
{
    if (d->jsonConfig.contains(key)) {
        d->jsonConfig[key] = value.toJsonValue();
    } else {
        d->jsonConfig.insert(key, value.toJsonValue());
    }
    return true;
}

QVariant AppEvent::configValue(const QString &key)
{
    return d->jsonConfig.value(key).toVariant();
}

QVariant AppEvent::configReadValue(const QString &key, bool *isok)
{
    QFile file("config.json");
    QByteArray data;
    if (file.open(QFile::ReadOnly | QFile::Text)) {
        data = file.readAll();
        file.close();
    }
    QJsonParseError jsonError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
    if (jsonError.error != QJsonParseError::NoError) {
        if (isok) {
            *isok = false;
        }
        return QVariant();
    }
    const QJsonObject object = jsonDoc.object();
    for (auto it = object.constBegin(); it != object.constEnd(); ++it) {
        if (it.key() == key) {
            if (isok) {
                *isok = true;
            }
            return object[key];
        }
    }
    if (isok) {
        *isok = false;
    }
    return QVariant();
}

bool AppEvent::configLoadJson(const QJsonObject &object)
{
    for (auto it = object.constBegin(); it != object.constEnd(); ++it) {
        const QString key = it.key();
        if (d->jsonConfig.contains(key)) {
            d->jsonConfig[key] = object[key];
        } else {
            d->jsonConfig.insert(key, object[key]);
        }
    }
    qDebug() << d->jsonConfig;
    return true;
}
bool AppEvent::configLoad()
{
    //
    QFile file("config.json");
    QByteArray data;
    if (file.open(QFile::ReadOnly | QFile::Text)) {
        data = file.readAll();
        file.close();
    }
    QJsonParseError jsonError;
    QJsonDocument jsonDoc = QJsonDocument::fromJson(data, &jsonError);
    if (jsonError.error != QJsonParseError::NoError) {
        return false;
    }
    const QJsonObject object = jsonDoc.object();
    for (auto it = object.constBegin(); it != object.constEnd(); ++it) {
        const QString key = it.key();
        if (d->jsonConfig.contains(key)) {
            d->jsonConfig[key] = object[key];
        } else {
            d->jsonConfig.insert(key, object[key]);
        }
    }
    return true;
}
bool AppEvent::configSave()
{
    QJsonDocument jsonDoc(d->jsonConfig);
    QString jsonString = jsonDoc.toJson(QJsonDocument::Indented);

    QFile file("config.json");
    QByteArray data;
    if (file.open(QFile::WriteOnly | QFile::Text)) {
        file.write(jsonString.toUtf8());
        file.close();
    }
    return true;
}

QJsonObject AppEvent::config() const
{
    return d->jsonConfig;
}

void AppEvent::serverLink(bool b)
{
    emit serverLinkSignals(b);
}

void AppEvent::unLockScreen()
{
    emit unLockScreenSignals();
}
