#pragma once

#include <memory>
#include <string>
#include <chrono>

#include "Address.hpp"
#include "message_protocol/MessageEndpoint.hpp"
#include "message_protocol/MessageConnection.hpp"
#include "message_protocol/MessageError.hpp"

#include <tl/expected.hpp>

namespace tw::net {

/**
 * Status of a server connection attempt or established connection.
 */
enum class ConnectionStatus { Idle, Connecting, Connected, Failed };

/**
 * Encapsulates a connection to a game server.
 */
class ServerConnection {
    using Clock = std::chrono::steady_clock;

    std::unique_ptr<msg::MessageEndpoint> m_endpoint;
    msg::MessageConnection*               m_server = nullptr;
    Address                               m_address;
    ConnectionStatus                      m_status = ConnectionStatus::Idle;
    std::string                           m_error;
    Clock::time_point                     m_started_at;

    static constexpr std::chrono::seconds CONNECT_TIMEOUT{5};

public:
    explicit ServerConnection(Address address);

    tl::expected<void, msg::MessageError> start();

    void update();

    ConnectionStatus status() const { return m_status; }

    const std::string& error() const { return m_error; }

    const Address& address() const { return m_address; }

    msg::MessageEndpoint* endpoint() const { return m_endpoint.get(); }

    msg::MessageConnection* server() const { return m_server; }
};

}
