BareGit
#pragma once

#include <optional>
#include <string>
#include <string_view>
#include <thread>

#include <mw/http_server.hpp>

#include "delivery_store.hpp"
#include "key_store.hpp"
#include "runtime_state.hpp"
#include "subscription_store.hpp"
#include "telegram_client.hpp"

namespace telegrammer
{

/// Serves authenticated API routes and translates service errors to JSON.
class ApiServer : public mw::HTTPServer
{
public:
    /// Construct an API server over the shared application components.
    ApiServer(mw::IPSocketInfo listen_info, KeyStore& keys,
              SubscriptionStore& subscriptions, DeliveryStore& deliveries,
              TelegramApi& telegram, RuntimeState& state);

    /// Stop the listener and join its serving thread during destruction.
    ~ApiServer();

    /// Bind synchronously, then start serving requests in a joined thread.
    mw::E<void> start();

    /// Stop accepting requests without destroying component dependencies.
    void stop();

    /// Wait for the serving thread to finish.
    void wait();

protected:
    /// Register routes and common HTTP server limits.
    void setup() override;

private:
    mw::IPSocketInfo listen_info_;
    KeyStore& keys_;
    SubscriptionStore& subscriptions_;
    DeliveryStore& deliveries_;
    TelegramApi& telegram_;
    RuntimeState& state_;
    std::thread server_thread_;

    bool authenticate(const Request& request, Response& response);
    bool requireJson(const Request& request, Response& response);
    std::optional<json> parseObject(const Request& request, Response& response);
    std::optional<int64_t> ownerId(const Response& response) const;

    static void writeSuccess(Response& response, const json& body,
                             int status = 200);
    static void writeNoContent(Response& response);
    static void writeError(Response& response, int status,
                           std::string_view code, std::string_view message,
                           std::optional<std::string_view> field =
                               std::nullopt,
                           std::optional<int> retry_after = std::nullopt);
    static void writeError(Response& response, const mw::Error& error);

    void send(const Request& request, Response& response);
    void subscribe(const Request& request, Response& response);
    void listSubscriptions(const Request& request, Response& response);
    void deleteSubscription(const Request& request, Response& response);
    void health(const Request& request, Response& response);
};

} // namespace telegrammer