// SPDX-License-Identifier: GPL-2.0-or-later
// SPDX-FileCopyrightText: 2007 Konrad Twardowski

#pragma once

#include "utils.h"

#include <QCheckBox>
#include <QColor>
#include <QSettings>

#ifdef KS_KF5
	#include <KConfigGroup>
#endif // KS_KF5

class Var final {
public:
	explicit Var(const QString &group, const QString &key, const bool defaultValue)
		: m_group(group), m_key(key), m_defaultVariant(defaultValue), m_lazyVariant(QVariant()) { }
	explicit Var(const QString &group, const QString &key, const int defaultValue)
		: m_group(group), m_key(key), m_defaultVariant(defaultValue), m_lazyVariant(QVariant()) { }
	explicit Var(const QString &group, const QString &key, const QColor &defaultValue)
		: m_group(group), m_key(key), m_defaultVariant(defaultValue), m_lazyVariant(QVariant()) { }
	explicit Var(const QString &group, const QString &key, const QString &defaultValue)
		: m_group(group), m_key(key), m_defaultVariant(defaultValue), m_lazyVariant(QVariant()) { }

	explicit operator bool() {
		return getBool();
	}

	[[nodiscard]] bool getBool() {
		return variant().toBool();
	}

	void setBool(const bool value) {
		m_lazyVariant.setValue(value);
	}

	[[nodiscard]] QColor getColor() {
		return variant().value<QColor>();
	}

	void setColor(const QColor &value) {
		m_lazyVariant.setValue(value);
	}

	[[nodiscard]] QVariant getDefault() const { return m_defaultVariant; }

	[[nodiscard]] int getInt() {
		return variant().value<int>();
	}

	void setInt(const int value) {
		m_lazyVariant.setValue(value);
	}

	[[nodiscard]] QString getString() {
		return variant().toString();
	}

	void setString(const QString &value) {
		m_lazyVariant.setValue(value);
	}

	QCheckBox *newCheckBox(const QString &text);
	void write(const bool sync = false);
	void write(QCheckBox *checkBox);
private:
	QString m_group;
	QString m_key;
	QVariant m_defaultVariant;
	QVariant m_lazyVariant;
	QVariant variant();
};

/**
 * A configuration reader/writer.
 *
 * @b WARNING: This class is not thread-safe.
 */
class Config final {
public:
	// HACK: need explicit "QString" type otherwise C++ will pick "bool" overload...
	inline static Var bootEntries                = Var("KShutdown Action reboot", "Entries", QString(""));
	inline static Var bootEntriesVisibleInMenu   = Var("KShutdown Action reboot", "Entries Visible In Menu", true);
	inline static Var bootEntriesVisibleInWindow = Var("KShutdown Action reboot", "Entries Visible In Window", true);
	inline static Var bootSetEntryCommand        = Var("KShutdown Action reboot", "Set Boot Entry Command", QString(""));

	inline static Var cancelDefault = Var("General", "Cancel Default", true);
	inline static Var confirmAction = Var("General", "Confirm Action", false);
	inline static Var countdownEnabled = Var("Countdown", "Enabled", true);
	inline static Var lockScreenBeforeHibernate = Var("General", "Lock Screen Before Hibernate", true);
	inline static Var minimizeToSystemTrayIcon = Var("General", "Minimize To System Tray Icon", true);
	inline static Var progressBarEnabled = Var("Progress Bar", "Enabled", false);

	inline static Var selectedAction  = Var("General", "Selected Action", QString("suspend"));
	inline static Var selectedTrigger = Var("General", "Selected Trigger", QString("time-from-now"));

	inline static Var systemTrayIconActiveColor = Var("General", "System Tray Icon Active Color", QColor(QColorConstants::Svg::orange));
	inline static Var systemTrayIconCustomColor = Var("General", "System Tray Icon Custom Color", false);
	inline static Var systemTrayIconEnabled     = Var("General", "System Tray Icon Enabled", true);
	inline static Var systemTrayIconNormalColor = Var("General", "System Tray Icon Normal Color", QColor(Qt::darkGray));
	inline static Var systemTrayIconUseTheme    = Var("General", "Use Theme Icon In System Tray", true);

	virtual ~Config();

	static QString getDataDirectory(const QString &subDirectory = "");
	static QString getPath() { return m_path; }
	static void init();
	static bool isPortable() { return m_portable; }
	static std::shared_ptr<QSettings> createDesktopEntry(const UPath &file);
	static std::shared_ptr<QSettings> openDesktopEntry(const UPath &file);

	[[nodiscard]] static bool readBool(const QString &group, const QString &key, const bool defaultValue);
	[[nodiscard]] static int readInt(const QString &group, const QString &key, const int defaultValue, const int min, const int max);
	[[nodiscard]] static QString readString(const QString &group, const QString &key, const QString &defaultValue);
	[[nodiscard]] static QVariant readVariant(const QString &group, const QString &key, const QVariant &defaultValue);
	static void writeBool(const QString &group, const QString &key, const bool value);
	static void writeInt(const QString &group, const QString &key, const int value);
	static void writeString(const QString &group, const QString &key, const QString &value);
	static void writeVariant(const QString &group, const QString &key, const QVariant &value);
	
	static void removeAllKeys(const QString &group);
	
	static void shutDown() {
		if (m_user) {
			delete m_user;
			m_user = 0;
		}
	}
	static void sync();
private:
	Q_DISABLE_COPY(Config)
#ifdef KS_KF5
	KConfig *m_engine;
	KConfigGroup m_group;
#else
	QSettings *m_engine;
#endif
	inline static bool m_portable = false;
	inline static Config *m_user = nullptr;
	inline static QSettings::Format m_desktopEntryFormat = QSettings::InvalidFormat;
	inline static QString m_path = "";

	explicit Config();
	void beginGroup(const QString &name);
	void endGroup();
	[[nodiscard]] QVariant get(const QString &key, const QVariant &defaultValue) const;
	void set(const QString &key, const QVariant &value);

	[[nodiscard]] static Config *user() {
		if (m_user == nullptr)
			m_user = new Config();

		return m_user;
	}
};
