#ifndef LACTIVATIONTOKEN_H
#define LACTIVATIONTOKEN_H

#include <LObject.h>
#include <LWeak.h>
#include <LEvent.h>
#include <memory>
#include <chrono>

/**
 * @brief Token for activating surfaces
 *
 * This class represents a token used in LActivationTokenManager::activateSurfaceRequest().
 *
 * For more details, refer to the LActivationTokenManager class documentation.
 */
class Louvre::LActivationToken final : public LObject
{
public:

    LCLASS_NO_COPY(LActivationToken)

    /**
     * @brief The client that requested the token creation.
     *
     * @note This may, but does not necessarily, refer to the same client that requests surface activation.
     *
     * @return A valid pointer during LActivationTokenManager::createTokenRequest(), but it may return `nullptr`
     *         if accessed later, for example, if the client has disconnected.
     */
    LClient *creator() const noexcept
    {
        return m_creator.get();
    }

    /**
     * @brief The surface of the client that created the token.
     *
     * This refers to the surface where the triggeringEvent() was sent.
     *
     * @note This is different from the surface intended to be activated.
     *
     * @warning Clients are not obligated to provide this hint, so this method may return `nullptr`.
     */
    LSurface *origin() const noexcept
    {
        return m_origin.get();
    }

    /**
     * @brief Triggering event
     *
     * Clients typically request token creation in response to an input event. The default implementation of
     * LActivationTokenManager::createTokenRequest() only accepts requests containing a valid triggeringEvent().
     *
     * @see origin()
     *
     * @warning This value is optional, if the client does not specify a triggering event, this method returns `nullptr`.
     */
    const LEvent *triggeringEvent() const noexcept
    {
        return m_triggeringEvent.get();
    }

    /**
     * @brief Number of times the token has been used to activate a surface.
     *
     * Incremented by 1 before each LActivationTokenManager::activateSurfaceRequest().
     */
    UInt32 timesUsed() const noexcept
    {
        return m_timesUsed;
    }

    /**
     * @brief Time the token was created.
     *
     * @see LActivationTokenManager::destroyTokensOlderThanMs().
     *
     * @return The time point when the token was created.
     */
    const std::chrono::time_point<std::chrono::steady_clock> &created() const noexcept
    {
        return m_created;
    }

    /**
     * @brief The app ID of the client to be activated.
     *
     * This value is optional, if the token creator does not assign an app ID, this method returns an empty string.
     */
    const std::string &toActivateAppId() const noexcept
    {
        return m_toActivateAppId;
    }

    /**
     * @brief The unique and random token string generated by Louvre.
     *
     * @return The token string.
     */
    const std::string &token() const noexcept
    {
        return *m_key;
    }

    /**
     * @brief Invalidates and destroys the token.
     *
     * Removes it from LActivationTokenManager::tokens().
     *
     * Once destroyed, no client will be able to use it to activate surfaces.
     *
     * @return An iterator to the next element in LActivationTokenManager::tokens().
     */
    const std::unordered_map<std::string, LActivationToken*>::iterator destroy() const noexcept;

private:
    friend class Protocols::XdgActivation::GXdgActivation;
    friend class Protocols::XdgActivation::RXdgActivationToken;

    LActivationToken(
        LClient *creator,
        LSurface *origin,
        LEvent *triggeringEvent,
        std::string &&toActivateAppId) noexcept;

    ~LActivationToken() { notifyDestruction(); };

    LWeak<LClient> m_creator;
    LWeak<LSurface> m_origin;
    std::unique_ptr<LEvent> m_triggeringEvent;
    std::string m_toActivateAppId;
    std::chrono::time_point<std::chrono::steady_clock> m_created {
        std::chrono::steady_clock::now()
    };
    UInt32 m_timesUsed { 0 };
    const std::string *m_key { nullptr };
};

#endif // LACTIVATIONTOKEN_H
