// SPDX-FileCopyrightText: 2024 Yury Gubich <blue@macaw.me>
// SPDX-License-Identifier: GPL-3.0-or-later

#pragma once

#include <memory>

#include <gloox/client.h>
#include <gloox/message.h>
#include <gloox/disco.h>
#include <gloox/connectionlistener.h>
#include <gloox/messagehandler.h>
#include <gloox/pubsubmanager.h>
#include <gloox/pubsubitem.h>
#include <gloox/pubsubresulthandler.h>

#include "shared/loggable.h"
#include "shared/utils.h"
#include "component/core.h"

class Connection:
    private Shared::Loggable,
    public gloox::ConnectionListener,
    public gloox::MessageHandler,
    public gloox::PubSub::ResultHandler
{
public:
    enum State {
        initial,
        disconnected,
        connected
    };

public:
    Connection(const std::shared_ptr<Core>& core);
    ~Connection() noexcept;

    void initialize();
    void deinitialize();
    void connect();
    void send(const std::string& jid, const std::string& body);
    void publish(const std::string& service, const std::string& node, const std::string& title, const std::string& body);
    
    static std::string errorTypeToString(gloox::StanzaErrorType err);

public:
    void onConnect() override;
    void onDisconnect(gloox::ConnectionError e) override;
    bool onTLSConnect(const gloox::CertInfo&) override;
    void handleMessage(const gloox::Message& message, gloox::MessageSession* session = 0) override;

    void handleItemPublication(const std::string& id, const gloox::JID& service, const std::string& node, const gloox::PubSub::ItemList& itemList, const gloox::Error* error = 0) override;

    // All other methods are not needed; make them no-op
    void handleItem(const gloox::JID&, const std::string&, const gloox::Tag*) override {}
    void handleItems(const std::string&, const gloox::JID&, const std::string&, const gloox::PubSub::ItemList&, const gloox::Error* = 0) override {}
    void handleItemDeletion(const std::string&, const gloox::JID&, const std::string&, const gloox::PubSub::ItemList&, const gloox::Error* = 0) override {}
    void handleSubscriptionResult(const std::string&, const gloox::JID&, const std::string&, const std::string&, const gloox::JID&, const gloox::PubSub::SubscriptionType, const gloox::Error* = 0) override {}
    void handleUnsubscriptionResult(const std::string&, const gloox::JID&, const gloox::Error* = 0) override {}
    void handleSubscriptionOptions(const std::string&, const gloox::JID&, const gloox::JID&, const std::string&, const gloox::DataForm*, const std::string& = gloox::EmptyString, const gloox::Error* = 0) override {}
    void handleSubscriptionOptionsResult(const std::string&, const gloox::JID&, const gloox::JID&, const std::string&, const std::string& = gloox::EmptyString, const gloox::Error* = 0) override {}
    void handleSubscribers(const std::string&, const gloox::JID&, const std::string&, const gloox::PubSub::SubscriptionList&, const gloox::Error* = 0) override {}
    void handleSubscribersResult(const std::string&, const gloox::JID&, const std::string&, const gloox::PubSub::SubscriberList*, const gloox::Error* = 0) override {}
    void handleAffiliates(const std::string&, const gloox::JID&, const std::string&, const gloox::PubSub::AffiliateList*, const gloox::Error* = 0) override {}
    void handleAffiliatesResult(const std::string&, const gloox::JID&, const std::string&, const gloox::PubSub::AffiliateList*, const gloox::Error* = 0) override {}
    void handleNodeConfig(const std::string&, const gloox::JID&, const std::string&, const gloox::DataForm*, const gloox::Error* = 0) override {}
    void handleNodeConfigResult(const std::string&, const gloox::JID&, const std::string&, const gloox::Error* = 0) override {}
    void handleNodeCreation(const std::string&, const gloox::JID&, const std::string&, const gloox::Error* = 0) override {}
    void handleNodeDeletion(const std::string&, const gloox::JID&, const std::string&, const gloox::Error* = 0) override {}
    void handleNodePurge(const std::string&, const gloox::JID&, const std::string&, const gloox::Error* = 0) override {}
    void handleSubscriptions(const std::string&, const gloox::JID&, const gloox::PubSub::SubscriptionMap&, const gloox::Error* = 0) override {}
    void handleAffiliations(const std::string&, const gloox::JID&, const gloox::PubSub::AffiliationMap&, const gloox::Error* = 0) override {}
    void handleDefaultNodeConfig(const std::string&, const gloox::JID&, const gloox::DataForm*, const gloox::Error* = 0) override {}

private:
    State state;
    std::shared_ptr<Core> core;
    std::unique_ptr<gloox::Client> gloox;
    std::unique_ptr<gloox::PubSub::Manager> pubsub;
};