// SPDX-FileCopyrightText: 2022 Contributors to Chatterino <https://chatterino.com>
//
// SPDX-License-Identifier: MIT

#pragma once

#include "providers/liveupdates/BasicPubSubClient.hpp"
// this needs to be included for the specialization
// of std::hash for Subscription
#include "providers/seventv/eventapi/Dispatch.hpp"  // for Twitch/KickUser
#include "providers/seventv/eventapi/Subscription.hpp"

#include <QPointer>

namespace chatterino {
class SeventvEventAPI;
class EmoteMap;
}  // namespace chatterino

namespace chatterino::seventv::eventapi {

struct Dispatch;
struct CosmeticCreateDispatch;
struct EntitlementCreateDeleteDispatch;

class Client : public BasicPubSubClient<Subscription, Client>,
               public std::enable_shared_from_this<Client>
{
public:
    Client(SeventvEventAPI &manager,
           std::chrono::milliseconds heartbeatInterval);

    void onOpen() /* override */;
    void onMessage(const QByteArray &msg) /* override */;

    std::chrono::milliseconds heartbeatInterval() const;
    void checkHeartbeat();

private:
    void handleDispatch(const Dispatch &dispatch);

    void onEmoteSetCreate(const Dispatch &dispatch);
    void onEmoteSetUpdate(const Dispatch &dispatch);
    void onUserUpdate(const Dispatch &dispatch);
    void onCosmeticCreate(const CosmeticCreateDispatch &cosmetic);
    void onEntitlementCreate(
        const EntitlementCreateDeleteDispatch &entitlement);
    void onEntitlementDelete(
        const EntitlementCreateDeleteDispatch &entitlement);

    std::atomic<std::chrono::time_point<std::chrono::steady_clock>>
        lastHeartbeat_;
    std::atomic<std::chrono::milliseconds> heartbeatInterval_;
    SeventvEventAPI &manager_;

    struct LastPersonalEmoteAssignment {
        QVarLengthArray<User, 1> connections;
        QString emoteSetID;
        std::shared_ptr<const EmoteMap> emoteSet;
    };

    /// This is a workaround for 7TV sending `CreateEntitlement` before
    /// `UpdateEmoteSet`. We only upsert emotes when a user gets assigned a
    /// new emote set, but in this case, we're upserting after updating as well.
    std::optional<LastPersonalEmoteAssignment> lastPersonalEmoteAssignment_;
};

}  // namespace chatterino::seventv::eventapi
