// SPDX-FileCopyrightText: 2024 Akseli Lahtinen <akselmo@akselmo.dev>
//
// SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL

#pragma once

#include "krdpserversettings.h"
#include "usersmodel.h"
#include <KQuickManagedConfigModule>
#include <qt6keychain/keychain.h>
#ifdef HAVE_SYSTEMD
#include <systemd/sd-journal.h>
#endif

class KRDPServerConfigImpl;
class QAbstractItemModel;

namespace SystemdService
{
Q_NAMESPACE
enum Status {
    Unknown,
    Running,
    Stopped,
    Failed
};
Q_ENUM_NS(Status);
}

class KRDPServerConfig : public KQuickManagedConfigModule
{
    Q_OBJECT
public:
    explicit KRDPServerConfig(QObject *parent, const KPluginMetaData &data);
    ~KRDPServerConfig() override;

    Q_PROPERTY(SystemdService::Status serverStatus READ serverStatus NOTIFY serverStatusChanged);
    Q_PROPERTY(QString errorMessage READ errorMessage NOTIFY errorMessageChanged);

    Q_PROPERTY(QString hostName READ hostName CONSTANT)
    Q_PROPERTY(bool managementAvailable READ managementAvailable CONSTANT)

    Q_PROPERTY(QAbstractItemModel *users READ usersModel CONSTANT)

    Q_INVOKABLE QString toLocalFile(const QUrl &url);

    Q_INVOKABLE void modifyUser(const QString &oldUsername, const QString &newUsername, const QString &newPassword);
    Q_INVOKABLE void addUser(const QString &username, const QString &password);
    Q_INVOKABLE void deleteUser(const QString &username);
    Q_INVOKABLE bool userExists(const QString &username);

    Q_INVOKABLE void readPasswordFromWallet(const QString &user);
    void writePasswordToWallet(const QString &user, const QString &password);
    void deletePasswordFromWallet(const QString &user);

    Q_INVOKABLE bool isH264Supported();
    Q_INVOKABLE QStringList listenAddressList();
    Q_INVOKABLE void toggleAutoconnect(const bool enabled);
    Q_INVOKABLE void toggleServer(const bool enabled);
    Q_INVOKABLE void restartServer();

    Q_INVOKABLE void generateCertificate();
    Q_INVOKABLE void copyAddressToClipboard(const QString &address);
    Q_INVOKABLE KRDPServerSettings *settings() const
    {
        return m_serverSettings;
    };

    Q_INVOKABLE void updateServerStatus();
    SystemdService::Status serverStatus() const;
    Q_INVOKABLE [[nodiscard]] bool isServerRunning() const;

    QString errorMessage() const;

    QString hostName() const;
    bool managementAvailable() const;
    QAbstractItemModel *usersModel() const
    {
        return m_usersModel;
    };

public Q_SLOTS:
    void save() override;
    void defaults() override;

Q_SIGNALS:
    void krdpServerSettingsChanged();
    void generateCertificateSucceeded();
    void generateCertificateFailed();
    void passwordLoaded(const QString &user, const QString &password);
    void keychainError(const QString &errorText);
    void serverStatusChanged();
    void errorMessageChanged();
    void isServerRunningChanged();

private:
    void setServerStatus(SystemdService::Status status);
    void setErrorMessage(const QString &errorMessage);
    void createRestoreToken();
    QStringList getLastJournalEntries(const QString &unit, const QString &invocationId);
#ifdef HAVE_SYSTEMD
    QString journalValue(sd_journal *journal, const QString &field);
#endif

    KRDPServerSettings *m_serverSettings;
    UsersModel *m_usersModel;
    Q_SLOT void servicePropertiesChanged();
    bool m_isH264Supported { false };
    SystemdService::Status m_currentServerStatus;
    QString m_lastErrorMessage;

    template<typename Output, typename Input>
    Output narrow(Input i)
    {
        Output o = i;
        if (i != Input(o)) {
            std::abort();
        }
        return o;
    }
};
