/*
 * Copyright (C) 2023, KylinSoft Co., Ltd.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 3, or (at your option)
 * any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <http://www.gnu.org/licenses/>.
 *
**/
#include "defaultinterface.h"
#include <QDebug>
#include <QStandardPaths>
#include <QSettings>
#include <QFile>
#include <QDir>
#include <QMimeDatabase>

#define BROWSERTYPE "x-scheme-handler/http"
#define MAILTYPE    "x-scheme-handler/mailto"
#define IMAGETYPE   "image/png"
#define AUDIOTYPE   "audio/x-vorbis+ogg"
#define VIDEOTYPE   "video/mp4"
#define TEXTTYPE    "text/plain"

#define LOCAL_CONFIG_DIR "/.config/"

QMap <QString , QVariant> DefaultInterface::mSysDefaultList;

static bool mimeTypeLessThan(const QMimeType &m1, const QMimeType &m2)
{
    return m1.name() < m2.name();
}

DefaultInterface::DefaultInterface()
{
    mLocalMimefile = QDir::homePath() + LOCAL_CONFIG_DIR + "mimeapps.list";
    getSystemDefaultAppList();
    mBrowserMimeTypeList << "x-scheme-handler/http" << "x-scheme-handler/https" << "x-scheme-handler/about" << "text/html";
    mMailMimeTypeList << "x-scheme-handler/mailto" << "application/x-extension-eml" << "message/rfc822";
    mTextMimeTypeList << "text/plain";
}

QMap<QString, QVariant> DefaultInterface::getSystemDefaultAppList()
{
    if (!mSysDefaultList.isEmpty()) {
        return mSysDefaultList;
    }
    QStringList mimeappsFileNames;
    const QString desktops = QString::fromLocal8Bit(qgetenv("XDG_CURRENT_DESKTOP"));
    const auto list = desktops.split(QLatin1Char(':'));
    for (const QString &desktop : list) {
        mimeappsFileNames.append(desktop.toLower() + QLatin1String("-mimeapps.list"));
    }
    const QStringList mimeappsDirs = QStandardPaths::standardLocations(QStandardPaths::GenericConfigLocation) + QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);

    for (const QString &dir : mimeappsDirs) {
        for (QString file : mimeappsFileNames) {
             // 系统目录配置文件
            QString filePath = dir + QLatin1Char('/') + file;
            if (QFile::exists(filePath)) {
                QSettings* mimeappFile = new QSettings(filePath, QSettings::IniFormat);
                mimeappFile->setIniCodec("utf-8");
                mSysDefaultList[BROWSERTYPE] = mimeappFile->value(QString("Default Applications/%1").arg(BROWSERTYPE)).toString();
                mSysDefaultList[AUDIOTYPE] = mimeappFile->value(QString("Default Applications/%1").arg(AUDIOTYPE)).toString();
                mSysDefaultList[VIDEOTYPE] = mimeappFile->value(QString("Default Applications/%1").arg(VIDEOTYPE)).toString();
                mSysDefaultList[IMAGETYPE] = mimeappFile->value(QString("Default Applications/%1").arg(IMAGETYPE)).toString();
                mSysDefaultList[TEXTTYPE] = mimeappFile->value(QString("Default Applications/%1").arg(TEXTTYPE)).toString();
                mSysDefaultList[MAILTYPE] = mimeappFile->value(QString("Default Applications/%1").arg(MAILTYPE)).toString();
                delete mimeappFile;
                mimeappFile = nullptr;
                return mSysDefaultList;
            }
        }
    }
    return mSysDefaultList;
}

QVariantList DefaultInterface::getDefaultApp(const QString &mimeType)
{
    qDBusRegisterMetaType<Service>();
    QVariantList list;
    KService::Ptr currentService;
    KService::Ptr preferredService = KApplicationTrader::preferredService(mimeType);

    if (QFile(mLocalMimefile).exists()) {
        QSettings* mimeappFile = new QSettings(mLocalMimefile, QSettings::IniFormat);
        mimeappFile->setIniCodec("utf-8");
        QString desktopFile = mimeappFile->value(QString("Added Associations/%1").arg(mimeType)).toString();
        if (!desktopFile.isEmpty()) {
            if (preferredService)
                currentService = preferredService;
        }
        delete mimeappFile;
        mimeappFile = nullptr;
    }

    if(preferredService  && preferredService->storageId().contains(mSysDefaultList[mimeType].toString())) {
        currentService = preferredService;
    }
    Service service;
    if (currentService) {
        service.icon = currentService->icon();
        service.name = currentService->name();
        service.storageId = currentService->storageId();
    }
    list.append(QVariant::fromValue(service));
    return list;
}

QVariantList DefaultInterface::getAppList(const QString &mimeType)
{
    qDBusRegisterMetaType<Service>();
    QVariantList list;
    QStringList applist;
    KApplicationTrader::queryByMimeType(mimeType, [&](const KService::Ptr &service) {
        if (service->exec().isEmpty() || (!service->serviceTypes().contains(mimeType)))
            return false;
        // 视频播放器屏蔽音乐
        if (mimeType == VIDEOTYPE && service->storageId().contains("kylin-music.desktop"))
            return false;
        if (applist.contains(service->name()))
            return false;
        applist.append(service->name());

        Service app;
        if (service) {
            app.icon = service->icon();
            app.name = service->name();
            app.storageId = service->storageId();
        }
        list.append(QVariant::fromValue(app));
        return true;
    });
    return list;
}

void DefaultInterface::setDefaultApp(const QString &storageId, const QString &mimeType)
{
    if (mimeType == BROWSERTYPE) {
        for (const QString str : mBrowserMimeTypeList)
            saveMimeTypeAssociation(str, storageId);
    } else if (mimeType == TEXTTYPE) {
        for (const QString str : mTextMimeTypeList)
            saveMimeTypeAssociation(str, storageId);
    } else if (mimeType == MAILTYPE) {
        for (const QString str : mMailMimeTypeList)
            saveMimeTypeAssociation(str, storageId);
    } else {
        QMimeDatabase datebase;
        auto list = datebase.allMimeTypes();
        const QString maj = QString(mimeType).left(QString(mimeType).indexOf(QLatin1Char('/')));
        std::sort(list.begin(), list.end(), mimeTypeLessThan);

        for (auto it = list.constBegin(); it != list.constEnd(); ++it) {
            const QString mimetype = it->name();
            if (maj == mimetype.left(mimetype.indexOf(QLatin1Char('/')))) {
                saveMimeTypeAssociation(mimetype, storageId);
            }
        }
    }
}

void DefaultInterface::saveMimeTypeAssociation(const QString &mime, const QString &storageId)
{
    KSharedConfig::Ptr profile = KSharedConfig::openConfig(QStringLiteral("mimeapps.list"), KConfig::NoGlobals, QStandardPaths::GenericConfigLocation);
    if (profile->isConfigWritable(true)) {
        KConfigGroup defaultApp(profile, "Default Applications");
        defaultApp.writeEntry(mime, QStringList(storageId));

        KConfigGroup addedApps(profile, QStringLiteral("Added Associations"));
        QStringList apps = addedApps.readXdgListEntry(mime);
        apps.removeAll(storageId);
        apps.prepend(storageId);
        addedApps.writeXdgListEntry(mime, apps);
        profile->sync();
    }
}

const QDBusArgument &operator<<(QDBusArgument &argument, const Service &service)
{
    argument.beginStructure();
    argument << service.icon;
    argument << service.name;
    argument << service.storageId;
    argument.endStructure();
    return argument;
}

const QDBusArgument &operator>>(const QDBusArgument &argument, Service &service)
{
    argument.beginStructure();
    argument >> service.icon;
    argument >> service.name;
    argument >> service.storageId;
    argument.endStructure();
    return argument;
}
