#pragma once

#include "connection.hpp"
#include "sasl_mechanism.hpp"

#include <string>
#include <unordered_set>
#include <span>

struct Connection;
struct IrcMsg;

enum class Casemap
{
    Rfc1459,
    Rfc1459_Strict,
    Ascii,
};

struct Chat {
    std::span<const irctag> tags;
    bool is_notice;
    char status_msg;
    std::string_view source;
    std::string_view target;
    std::string_view message;
};

/**
 * @brief Thread to track this connection's identity, and IRC state.
 *
 */
class Client
{
    Connection &connection_;

    std::string nickname_;
    std::string mode_;
    std::unordered_set<std::string> channels_;

    // RPL_ISUPPORT state
    std::unordered_map<std::string, std::string> isupport_;
    std::unique_ptr<SaslMechanism> sasl_mechanism_;

    Casemap casemap_;
    std::string channel_prefix_;
    std::string status_msg_;

    std::unordered_map<std::string, std::string> caps_available_;
    std::unordered_set<std::string> caps_;

    auto on_welcome(const IrcMsg &irc) -> void;
    auto on_isupport(const IrcMsg &irc) -> void;
    auto on_nick(const IrcMsg &irc) -> void;
    auto on_umodeis(const IrcMsg &irc) -> void;
    auto on_join(const IrcMsg &irc) -> void;
    auto on_kick(const IrcMsg &irc) -> void;
    auto on_part(const IrcMsg &irc) -> void;
    auto on_mode(const IrcMsg &irc) -> void;
    auto on_cap(const IrcMsg &irc) -> void;
    auto on_authenticate(std::string_view) -> void;
    auto on_registered() -> void;
    auto on_chat(bool, const IrcMsg &irc) -> void;

public:
    boost::signals2::signal<void()> sig_registered;
    boost::signals2::signal<void(const std::unordered_map<std::string, std::string> &)> sig_cap_ls;
    boost::signals2::signal<void(const Chat &)> sig_chat;

    Client(Connection &connection)
        : connection_{connection}
        , casemap_{Casemap::Rfc1459}
        , channel_prefix_{"#&"}
        , status_msg_{"+@"}
    {
    }

    auto get_connection() -> Connection & { return connection_; }

    static auto start(Connection &) -> std::shared_ptr<Client>;

    auto start_sasl(std::unique_ptr<SaslMechanism> mechanism) -> void;

    auto get_connection() const -> std::shared_ptr<Connection>
    {
        return connection_.shared_from_this();
    }

    auto get_my_nick() const -> const std::string &;
    auto get_my_mode() const -> const std::string &;
    auto get_my_channels() const -> const std::unordered_set<std::string> &;

    auto list_caps() -> void;

    auto is_my_nick(std::string_view nick) const -> bool;
    auto is_my_mask(std::string_view mask) const -> bool;
    auto is_channel(std::string_view name) const -> bool;

    auto casemap(std::string_view) const -> std::string;
    auto casemap_compare(std::string_view, std::string_view) const -> int;

    auto shutdown() -> void;
};