/*
 * This file is part of smolbote. It's copyrighted by the contributors recorded
 * in the version control history of the file, available from its original
 * location: https://neueland.iserlohn-fortress.net/gitea/aqua/smolbote
 *
 * SPDX-License-Identifier: GPL-3.0
 */

#include "webprofilemanager.h"
#include "webprofile.h"
#include <QFileInfo>
#include <QWebEngineSettings>

WebProfileManager::WebProfileManager(const QHash<QString, QString> &profileSection, QObject *parent)
    : QObject(parent)
    , defaults(profileSection)
{
}

WebProfileManager::~WebProfileManager()
{
    for(Profile p : profiles) {
        if(p.selfDestruct && p.settings != nullptr) {
            if(!p.ptr->isOffTheRecord()) {
                if(!p.ptr->persistentStoragePath().isEmpty())
                    QDir(p.ptr->persistentStoragePath()).removeRecursively();
                if(!p.ptr->cachePath().isEmpty())
                    QDir(p.ptr->cachePath()).removeRecursively();
            }
            const QString filename = p.settings->fileName();
            delete p.settings;
            QFile::remove(filename);
        } else if(p.settings != nullptr) {
            p.settings->sync();
            delete p.settings;
        }
    }
}

WebProfile *WebProfileManager::profile(const QString &id, const QString &path, bool isOffTheRecord)
{
    // Check if profile exists
    if(profiles.contains(id))
        return profiles.value(id).ptr;

    Profile profile;

    if(!path.isEmpty())
        profile.settings = new QSettings(path, QSettings::IniFormat);

    // QWebEngineCore cleans up profiles automatically, so no need to set parent
    profile.ptr = [id, isOffTheRecord, profile]() {
        if(profile.value("otr", isOffTheRecord).toBool())
            return new WebProfile(/* name */ profile.value("name", id).toString(), /* parent */ nullptr);
        else
            return new WebProfile(/* storageName */ id, /* name */ profile.value("name", id).toString(), /* parent */ nullptr);
    }();
    if(profile.settings != nullptr)
        profile.settings->setParent(profile.ptr);

    connect(profile.ptr, &WebProfile::nameChanged, profile.settings, [profile](const QString &name) {
        profile.settings->setValue("name", name);
    });

    profile.ptr->setSearch(profile.value("search", defaults.value("profile.search")).toString());
    connect(profile.ptr, &WebProfile::searchChanged, profile.settings, [profile](const QString &url) {
        profile.settings->setValue("search", url);
    });

    profile.ptr->setHomepage(profile.value("homepage", defaults.value("profile.homepage")).toUrl());
    connect(profile.ptr, &WebProfile::homepageChanged, profile.settings, [profile](const QUrl &url) {
        profile.settings->setValue("homepage", url);
    });

    profile.ptr->setNewtab(profile.value("newtab", defaults.value("profile.newtab")).toUrl());
    connect(profile.ptr, &WebProfile::newtabChanged, profile.settings, [profile](const QUrl &url) {
        profile.settings->setValue("newtab", url);
    });

    if(profile.settings != nullptr) {
        profile.settings->beginGroup("properties");
        {
            const auto keys = profile.settings->childKeys();
            for(const QString &key : keys) {
                profile.ptr->setProperty(qUtf8Printable(key), profile.settings->value(key));
            }
        }
        profile.settings->endGroup(); // properties
        connect(profile.ptr, &WebProfile::propertyChanged, [profile](const QString &property, const QVariant &value) {
            profile.settings->setValue("properties/" + property, value);
        });

        profile.settings->beginGroup("attributes");
        {
            const auto keys = profile.settings->childKeys();
            auto *settings = profile.ptr->settings();
            for(const QString &key : keys) {
                auto attribute = static_cast<QWebEngineSettings::WebAttribute>(key.toInt());
                settings->setAttribute(attribute, profile.settings->value(key).toBool());
            }
        }
        profile.settings->endGroup();
        connect(profile.ptr, &WebProfile::attributeChanged, [profile](const QWebEngineSettings::WebAttribute attr, const bool value) {
            profile.settings->setValue("attributes/" + QString::number(attr), value);
        });

        // headers
        profile.settings->beginGroup("headers");
        for(const QString &key : profile.settings->childKeys()) {
            profile.ptr->setHttpHeader(key.toLatin1(), profile.settings->value(key).toString().toLatin1());
        }
        profile.settings->endGroup();
        connect(profile.ptr, &WebProfile::headerChanged, [profile](const QString &name, const QString &value) {
            profile.settings->setValue("headers/" + name, value);
        });
        connect(profile.ptr, &WebProfile::headerRemoved, [profile](const QString &name) {
            profile.settings->remove("headers/" + name);
        });

    } // profile.settings != nullptr

    profiles[id] = profile;
    return profile.ptr;
}

void WebProfileManager::deleteProfile(const QString &id)
{
    if(profiles.contains(id)) {
        profiles[id].selfDestruct = true;
    }
}

void WebProfileManager::profileMenu(QMenu *menu, const std::function<void(WebProfile *)> &callback, WebProfile *current, bool checkable) const
{
    auto *group = new QActionGroup(menu);
    connect(menu, &QMenu::aboutToHide, group, &QActionGroup::deleteLater);

    for(const auto &profile : profiles) {
        auto *action = menu->addAction(profile.ptr->name(), profile.ptr, [profile, callback]() {
            callback(profile.ptr);
        });
        action->setCheckable(checkable);
        if(profile.ptr == current)
            action->setChecked(true);
        group->addAction(action);
    }
}