#ifndef SERVER_RESPONSE_CONTAINERS_H
#define SERVER_RESPONSE_CONTAINERS_H

#include <QList>
#include <QPair>
#include <libcockatrice/protocol/pb/server_message.pb.h>

namespace google
{
namespace protobuf
{
class Message;
}
} // namespace google
class Server_Game;

class GameEventStorageItem
{
public:
    enum EventRecipient
    {
        SendToPrivate = 0x01,
        SendToOthers = 0x02
    };
    Q_DECLARE_FLAGS(EventRecipients, EventRecipient)
private:
    GameEvent *event;
    EventRecipients recipients;

public:
    GameEventStorageItem(const ::google::protobuf::Message &_event, int _playerId, EventRecipients _recipients);
    ~GameEventStorageItem();

    [[nodiscard]] const GameEvent &getGameEvent() const
    {
        return *event;
    }
    [[nodiscard]] EventRecipients getRecipients() const
    {
        return recipients;
    }
};
Q_DECLARE_OPERATORS_FOR_FLAGS(GameEventStorageItem::EventRecipients)

class GameEventStorage
{
private:
    ::google::protobuf::Message *gameEventContext;
    QList<GameEventStorageItem *> gameEventList;
    int privatePlayerId;
    int forcedByJudge = -1;
    bool overwriteOwnership = false;

public:
    GameEventStorage();
    ~GameEventStorage();

    void setGameEventContext(const ::google::protobuf::Message &_gameEventContext);
    [[nodiscard]] ::google::protobuf::Message *getGameEventContext() const
    {
        return gameEventContext;
    }
    [[nodiscard]] const QList<GameEventStorageItem *> &getGameEventList() const
    {
        return gameEventList;
    }
    [[nodiscard]] int getPrivatePlayerId() const
    {
        return privatePlayerId;
    }
    void setForcedByJudge(int playerId)
    {
        forcedByJudge = playerId;
    }
    void setOverwriteOwnership(bool shouldOverwriteOwnership)
    {
        overwriteOwnership = shouldOverwriteOwnership;
    }

    void enqueueGameEvent(const ::google::protobuf::Message &event,
                          int playerId,
                          GameEventStorageItem::EventRecipients recipients = GameEventStorageItem::SendToPrivate |
                                                                             GameEventStorageItem::SendToOthers,
                          int _privatePlayerId = -1);
    void sendToGame(Server_Game *game);
};

class ResponseContainer
{
private:
    int cmdId;
    ::google::protobuf::Message *responseExtension;
    QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *>> preResponseQueue, postResponseQueue;

public:
    ResponseContainer(int _cmdId);
    ~ResponseContainer();

    [[nodiscard]] int getCmdId() const
    {
        return cmdId;
    }
    void setResponseExtension(::google::protobuf::Message *_responseExtension)
    {
        responseExtension = _responseExtension;
    }
    [[nodiscard]] ::google::protobuf::Message *getResponseExtension() const
    {
        return responseExtension;
    }
    void enqueuePreResponseItem(ServerMessage::MessageType type, ::google::protobuf::Message *item)
    {
        preResponseQueue.append(qMakePair(type, item));
    }
    void enqueuePostResponseItem(ServerMessage::MessageType type, ::google::protobuf::Message *item)
    {
        postResponseQueue.append(qMakePair(type, item));
    }
    [[nodiscard]] const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *>> &
    getPreResponseQueue() const
    {
        return preResponseQueue;
    }
    [[nodiscard]] const QList<QPair<ServerMessage::MessageType, ::google::protobuf::Message *>> &
    getPostResponseQueue() const
    {
        return postResponseQueue;
    }
};

#endif
