/*
 * SPDX-FileCopyrightText: 2026 ChromiumOS-Guy <chromiumos-guy-opensource@proton.me>
 * SPDX-License-Identifier: GPL-3.0-or-later
 */

#include "Settings.h"
#include "dbus_types.h"
#include "portal_settings_adaptor.h"

#include <QColor>
#include <QFile>
#include <QSettings>
#include <QStandardPaths>
#include <QDebug>
#include <QDBusError>
#include <QDBusMetaType>

#include <algorithm>

#define THEME_SUBPATH "lomiri-ui-toolkit/theme.ini"
#define DARK_THEME "Lomiri.Components.Themes.SuruDark"
#define WHITE_THEME "Lomiri.Components.Themes.Ambiance"

// Lomiri accent orange (#E95420) as scRGB doubles.
static DBusColor lomiriAccent()
{
    return DBusColor{ QColor::fromRgbF(0.914, 0.329, 0.125) };
}


namespace portals {

Settings::Settings(QObject *parent)
    : QObject(parent)
    , m_configPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)
                   + "/" + THEME_SUBPATH)
{
    qDBusRegisterMetaType<DBusColor>();
    qDBusRegisterMetaType<QMap<QString, QVariantMap>>();

    if (!QFile::exists(m_configPath)) {
        qFatal("Settings: toolkit theme file missing at %s", qUtf8Printable(m_configPath));
    }

    m_watcher = new QFileSystemWatcher(this);
    m_watcher->addPath(m_configPath);
    connect(m_watcher, &QFileSystemWatcher::fileChanged, this, &Settings::handleThemeChange);

    m_lastColorScheme = getLomiriColorScheme();

    new SettingsAdaptor(this);
}

Settings::ColorScheme Settings::getLomiriColorScheme()
{
    QSettings settings(m_configPath, QSettings::IniFormat);
    QString theme = settings.value("theme").toString();

    if (theme == DARK_THEME)
        return ColorScheme::PreferDark;
    if (theme == WHITE_THEME)
        return ColorScheme::PreferWhite;
    return ColorScheme::NoPreference;
}

void Settings::handleThemeChange(const QString &path)
{
    // If the file was deleted/recreated, re-add it to the watcher
    m_watcher->addPath(path);

    uint current = getLomiriColorScheme();

    qDebug() << "Theme changed. Current theme value:" << current << "Last:" << m_lastColorScheme;

    if (current != m_lastColorScheme) {
        m_lastColorScheme = current;
        emit SettingChanged(QStringLiteral("org.freedesktop.appearance"),
                              QStringLiteral("color-scheme"),
                              QDBusVariant(QVariant::fromValue(current)));
    }
}

QVariantMap Settings::appearanceSettings()
{
    QVariantMap appearance;
    appearance[QStringLiteral("color-scheme")] = getLomiriColorScheme();
    appearance[QStringLiteral("accent-color")] = QVariant::fromValue(lomiriAccent());
    appearance[QStringLiteral("contrast")] = 0u;
    appearance[QStringLiteral("reduced-motion")] = 0u;
    return appearance;
}

QDBusVariant Settings::Read(const QString &ns, const QString &key)
{
    if (ns != QStringLiteral("org.freedesktop.appearance")) {
        sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("Unknown namespace: %1").arg(ns));
        return QDBusVariant();
    }

    const QVariantMap appearance = appearanceSettings();
    if (!appearance.contains(key)) {
        sendErrorReply(QDBusError::InvalidArgs, QStringLiteral("Unknown key: %1").arg(key));
        return QDBusVariant();
    }

    return QDBusVariant(appearance.value(key));
}

QMap<QString, QVariantMap> Settings::ReadAll(const QStringList &namespaces)
{
    QMap<QString, QVariantMap> result;
    // TODO: namespace filtering is broken for patterns like "org.freedesktop.appearance*"
    // (wildcardToRegularExpression matches a trailing glob against the whole namespace,
    // which incorrectly matches "org.freedesktop.appearance.foo"). File an issue and fix
    // properly; for now always return all namespaces.
    bool all = true;

    if (all)
        result[QStringLiteral("org.freedesktop.appearance")] = appearanceSettings();
    return result;
}

}