#include "functionsparser.h"
#include "deepinabilitymanager.h"
#include "deepinmultimedia.h"

#include <QCoreApplication>
#include <QTimer>
#include <QDebug>
#include <QUrl>
#include <QUrlQuery>
#include <QJsonDocument>
#include <QJsonObject>
#include <QStringList>
#include <QDesktopServices>
#include <QProcess>
#include <QDBusInterface>

#include <QLoggingCategory>
Q_DECLARE_LOGGING_CATEGORY(logTools)

FunctionsParser::FunctionsParser(const QJsonObject &function)
    : QThread(nullptr)
    , m_function(function)
{

}

FunctionsParser::~FunctionsParser()
{

}

int FunctionsParser::exitCode()
{
    return m_exitCode;
}

QString FunctionsParser::outputString()
{
    return m_outputString;
}

QString FunctionsParser::directOutput() const
{
    return m_directOutput;
}

void FunctionsParser::sendMailFunction(const QJsonObject &argumentsObj)
{
    qCDebug(logTools) << "Preparing to send email:" << argumentsObj;
    QString subject = argumentsObj.value("subject").toString();
    QString content = argumentsObj.value("content").toString();
    QStringList toList = argumentsObj.value("to").toString().split(",");
    QStringList ccList = argumentsObj.value("cc").toString().split(",");
    QStringList bccList = argumentsObj.value("bcc").toString().split(",");

    // 创建一个mailto链接
    QUrl mailtoUrl;
    QUrlQuery queryItem;
    mailtoUrl.setScheme("mailto");

    // 设置收件人
    if (!toList.join(",").isEmpty()) {
        queryItem.addQueryItem("to", toList.join(","));
    }

    // 设置抄送人
    if (!ccList.join(",").isEmpty()) {
        queryItem.addQueryItem("cc", ccList.join(","));
    }

    // 设置密送人
    if (!bccList.join(",").isEmpty()) {
        queryItem.addQueryItem("bcc", bccList.join(","));
    }

    // 设置主题
    if (!subject.isEmpty()) {
        queryItem.addQueryItem("subject", QUrl::toPercentEncoding(subject));
    }

    // 设置正文
    if (!content.isEmpty()) {
        queryItem.addQueryItem("body", QUrl::toPercentEncoding(content));
    }

    queryItem.addQueryItem("type", "1");

    mailtoUrl.setQuery(queryItem);
    openUrl(mailtoUrl.toString());
}

void FunctionsParser::openUrl(const QString &url)
{
    qCDebug(logTools) << "Attempting to open URL:" << url;
    QProcess process;
    process.setProgram("xdg-open");
    process.setArguments({url});
    process.start();
    process.waitForFinished(5000);
    int exitCode = process.exitCode();

    QString outputString;
    QString standardOutput = process.readAllStandardOutput();
    QStringList outLst = standardOutput.split(":");
    if (!outLst.isEmpty())
        outputString = outLst.last();

    if (outputString.isEmpty())
        outputString = standardOutput;

    m_exitCode = exitCode;
    m_outputString = outputString;

    if (exitCode != 0)
        qCWarning(logTools) << "Failed to open URL:" << url << "Exit code:" << exitCode << "Standard Output:" << outputString;
}

void FunctionsParser::openExec(const QString &mimeType)
{
    qCDebug(logTools) << "Looking up default application for MIME type:" << mimeType;
    QProcess process;
    QString command = QString("xdg-mime query default %1").arg(mimeType);
    process.start(command);
    process.waitForFinished(5000);
    m_exitCode = process.exitCode();

    QString outputString;
    QStringList outLst = QString(process.readAllStandardOutput()).split(":");
    if (!outLst.isEmpty())
        outputString = outLst.last();

    m_outputString = outputString;
    
    if (m_exitCode != 0) {
        qCWarning(logTools) << "Failed to query default application for MIME type:" << mimeType
                           << "Exit code:" << m_exitCode
                           << "Error output:" << outputString;
        return;
    }
    qCInfo(logTools) << "Exit code:" << m_exitCode << "Standard Output:" << outputString;

    outputString = outputString.trimmed();
    if (!outputString.endsWith(".desktop")) {
        m_exitCode = 1;
        qCWarning(logTools) << "FunctionsParser::openExec " << outputString;
        return;
    }

    QDBusInterface notification("com.deepin.SessionManager", "/com/deepin/StartManager", "com.deepin.StartManager", QDBusConnection::sessionBus());
    QList<QVariant> args;
    args.append("/usr/share/applications/" + outputString);
    QString error = notification.callWithArgumentList(QDBus::Block, "Launch", args).errorMessage();
    if (!error.isEmpty()) {
        m_exitCode = 1;
        m_outputString = error;
        qCCritical(logTools) << "Failed to launch application:" << error;
    }
}

void FunctionsParser::run()
{
    qCDebug(logTools) << "Starting function execution";
    m_exitCode = 0;
    m_outputString.clear();

    OSCallContext content;
    content.error = OSCallContext::NonError;

    const QString &funName = m_function.value("name").toString();
    const QJsonObject &argumentsObj = QJsonDocument::fromJson(m_function.value("arguments").toString().toUtf8()).object();
    qCInfo(logTools) << QString("FunctionCalling-functionName:%1  arguments:%2").arg(funName).arg(m_function.value("arguments").toString());
    if (funName == "sendMail") {
        sendMailFunction(argumentsObj);
    } else if (funName == "openBluetooth") {
        content = UosAbility()->doBluetoothConfig(argumentsObj.value("switch").toBool());
    } else if (funName == "openScreenMirroring") {
        content = UosAbility()->doScreenMirroring();
    } else if (funName == "switchNoDisturbMode") {
        content = UosAbility()->doNoDisturb(argumentsObj.value("switch").toBool());
    } else if (funName == "switchWallpaper") {
        content = UosAbility()->doWallpaperSwitch();
    } else if (funName == "organizeDesktop") {
        content = UosAbility()->doDesktopOrganize(argumentsObj.value("switch").toBool());
    } else if (funName == "switchDockMode") {
        QString modestr = argumentsObj.value("mode").toString();
        int mode = -1;
        if (modestr == "Fashion")
            mode = 0;
        else if (modestr == "Efficent")
            mode = 1;
        else
            qCWarning(logTools) << "Function name:" << funName << "function args error:" << argumentsObj;

        content = UosAbility()->doDockModeSwitch(mode);
    } else if (funName == "switchSystemTheme") {
        QString modestr = argumentsObj.value("theme").toString();
        int mode = -1;
        if (modestr == "Light")
            mode = 0;
        else if (modestr == "Dark")
            mode = 1;
        else if (modestr == "Auto")
            mode = 2;
        else
            qCWarning(logTools) << "Function name:" << funName << "function args error:" << argumentsObj;

        content = UosAbility()->doSystemThemeSwitch(mode);
    } else if (funName == "switchEyesProtection") {
        content = UosAbility()->doDiplayEyesProtection(argumentsObj.value("switch").toBool());
    } else if (funName == "displayBrightness") {
        int percent = argumentsObj.value("percent").toInt();
        int adjustment = argumentsObj.value("adjustment").toInt();
        content = UosAbility()->doDiplayBrightness(percent, adjustment);
    } else if (funName == "launchApplication") {
        QString appId = argumentsObj.value("appid").toString();
        // 由于目前function call太多，执行打开应用指令时模型推理会导致混淆，从而导致
        // switch参数丢失或者识别为非function call而直接输出问答。
        // 经过测试在执行关闭应用命令时,switch参数有效存在且为false。
        // 因此这里使用规避方案，让switch默认为true，以解决模型推理导致的参数丢失问题。
        bool on = true;
        if (argumentsObj.contains("switch"))
            on = argumentsObj.value("switch").toBool();
        content = UosAbility()->doAppLaunch(appId, on);
    } else if (funName == "createSchedule") {
        QString subject   = argumentsObj.value("subject").toString();
        QString startTime = argumentsObj.value("startTime").toString();
        QString endTime   = argumentsObj.value("endTime").toString();
        content = UosAbility()->doCreateSchedule(subject, startTime, endTime);
    } else if (funName == "systemTotalMemory") {
        content = UosAbility()->getSystemMemory();
    } else if (funName == "switchWifi") {
        content = UosAbility()->switchWifi(argumentsObj.value("switch").toBool());
    } else if (funName == "systemLanguageSetting") {
        content = UosAbility()->doSystemLanguageSetting();
    } else if (funName == "switchPerformanceMode") {
        QString mode = argumentsObj.value("mode").toString();
        bool isOpen = argumentsObj.value("switch").toBool();
        content = UosAbility()->doPerformanceModeSwitch(mode, isOpen);
    } else if (funName == "shutdownFront") {
        content = UosAbility()->openShutdownFront();
    } else if (funName == "screenShot") {
        content = UosAbility()->openScreenShot();
    } else if (funName == "switchDisplayMode") {
        QString modestr = argumentsObj.value("mode").toString();

        int mode = -1;
        if (modestr == "Copy")
            mode = 1;
        else if (modestr == "Extend")
            mode = 2;
        else
            qCWarning(logTools) << "Function name:" << funName << "function args error:" << argumentsObj;

        content = UosAbility()->doDisplayModeSwitch(mode);
    } else if (funName == "switchScreen") {
        content = UosAbility()->switchScreen();
    } else if (funName == "grandSearch") {
        content = UosAbility()->openGrandSearch();
    } else if (funName == "volumeAdjustment") {
        content = UosAbility()->volumeAdjustment(argumentsObj);
    } else if (funName == "stateControl") {
        content = UosAbility()->doStateControl(argumentsObj.value("control").toString());
    } else if (funName == "seek") {
        content = UosAbility()->doSeek(argumentsObj.value("offset").toInt());
    } else {
        content.error = OSCallContext::NotImpl;
        content.errorInfo = funName + QCoreApplication::translate("FunctionsParser", "Function not available");
    }

    if (content.error != OSCallContext::NonError) {
        qCWarning(logTools) << "Function execution failed:" << funName 
                           << "Error code:" << content.error
                           << "Error info:" << content.errorInfo
                           << "Function:" << m_function;
        m_exitCode = content.error;
        m_outputString = content.errorInfo;
    }

    m_directOutput = content.output;
}
