/**
 * Copyright (c) 2022
 *    Marcus Britanicus (https://gitlab.com/marcusbritanicus)
 *    Abrar (https://gitlab.com/s96Abrar)
 *    rahmanshaber (https://gitlab.com/rahmanshaber)
 *
 * DFL Login1 class implements a part of the systemd logind dbus protocol.
 **/

#pragma once

#include <QtCore>
#include <QtDBus>

namespace DFL {
    class Login1;
}

struct login1_impl_t;
typedef struct login1_impl_t Login1Impl;

class DFL::Login1 : public QObject {
    Q_OBJECT;

    public:
        enum InhibitorLock {
            SleepLock        = 1 << 0,
            ShutdownLock     = 1 << 1,
            IdleLock         = 1 << 2,
            PowerKeyLock     = 1 << 3,
            SuspendKeyLock   = 1 << 4,
            HibernateKeyLock = 1 << 5,
            LidSwitchLock    = 1 << 6,
        };
        Q_DECLARE_FLAGS( InhibitorLocks, InhibitorLock );

        /** Define the */
        typedef struct login1_inhibitor_t {
            QString  what;
            QString  who;
            QString  why;
            QString  mode;
            uint32_t uid;
            uint32_t pid;
        } Inhibitor;

        typedef QList<Inhibitor> Inhibitors;

        Login1( QObject *parent = nullptr );
        ~Login1();

        /** Acquire/Release inhibitor locks */
        void acquireInhibitLocks( DFL::Login1::InhibitorLocks locks );
        void releaseInhibitLocks();

        /** These are the inhibitors acquired by us */
        DFL::Login1::Inhibitors acquiredInhibitors();

        /** These are the inhibitors acquired globally */
        DFL::Login1::Inhibitors listInhibitors();

        /** Set the brightness of all the displays */
        [[deprecated("Use bool setBrightness( QString, QString, uint ) instead")]]
        bool setBrightness( qreal value );

        /** Set the brightness of the given display */
        bool setBrightness( QString, QString, uint );

        /**
         * Handle various requests.
         * These requests are meant to come from the DE that's using this lib.
         * An action request on this channel will simply release the suitable lock,
         * and perform the action, without intimating the user.
         *
         * Following action requests are allowed:
         *  - [Can]Suspend
         *  - [Can]SuspendThenHibernate
         *  - [Can]Hibernate
         *  - [Can]HybridSleep
         *  - [Can]PowerOff
         *  - [Can]Reboot
         *  - [Un]LockSession
         * All the Can* queries return -2/-1/0/1, representing NA, Challenge, No, and Yes.
         * All the other requests return 0/1 indicating failure or success.
         * All invalid queries/requests will return 0 indicating a failure.
         */
        int request( QString );

        /**
         * Schedule a power event of type poweroff or reboot or cancel.
         * @type is thhepower event type: poweroff, reboot or cancel
         * @usec is the time at which the power event is scheduled, in
         * microseconds since epoch.
         * Returns 0 on failure.
         * Returns 1 on success.
         * Returns 2 if usec is invalid.
         */
        int schedulePowerEvent( QString type, qulonglong usec );

        /**
         * Helper function
         * Schedule a power event of type poweroff or reboot or cancel.
         * @type is thhepower event type: poweroff, reboot or cancel
         * @usec is microseconds from now, the power event is scheduled
         * Calls schedulePowerEvent(...)
         */
        int schedulePowerEventIn( QString type, qulonglong usec );

        /**
         * Helper function
         * Schedule a power event of type poweroff or reboot or cancel.
         * @type is thhepower event type: poweroff, reboot or cancel
         * @dt is date-time at which the power event is scheduled
         * Calls schedulePowerEvent(...)
         */
        int schedulePowerEventAt( QString type, QDateTime dt );

    private:
        Login1Impl *impl;

        /**
         * PrepareForSleep(...) is called when Suspend/Hibernate is requested. This request
         * is simply ignored by us. We expect the users to use the Power/Logout Menu of the DE.
         * We're interested in waking up from sleep, or if the Sleep request failed to re-acquire
         * the sleep inhibitor lock.
         */
        void PrepareForSleep( bool active );

        /**
         * PrepareForShutdown(...) is called when PowerOff/Reboot is requested. This request
         * is simply ignored by us. We expect the users to use the Power/Logout Menu of the DE.
         * We're interested in Sleep request failing, so that we can re-acquire the shutdown
         * inhibitor lock.
         */
        void PrepareForShutdown( bool active );

        /**
         * Lock() is emitted when an external entity has requested that the screen be locked.
         * We can honour this request, by informing the DE about it.
         */
        void LockSession();

        /**
         * Unlock() is emitted when an external entity has requested that the screen be unlocked.
         * We can honour this request, by informing the DE about it.
         */
        void UnlockSession();

    Q_SIGNALS:
        /**
         * Inform the caller that an external process requested
         */
        // void
};

Q_DECLARE_OPERATORS_FOR_FLAGS( DFL::Login1::InhibitorLocks );
Q_DECLARE_METATYPE( DFL::Login1::Inhibitor );

QDBusArgument &operator<<( QDBusArgument& arg, const DFL::Login1::Inhibitor& inhibitor );
const QDBusArgument &operator>>( const QDBusArgument& arg, DFL::Login1::Inhibitor& inhibitor );
