BareGit
#pragma once

#include <atomic>
#include <memory>
#include <string>
#include <thread>

#include "api_server.hpp"
#include "database.hpp"
#include "dispatcher.hpp"
#include "key_store.hpp"
#include "poller.hpp"
#include "runtime_state.hpp"
#include "subscription_store.hpp"
#include "telegram_client.hpp"

namespace telegrammer
{

/// Contains the validated settings and held lock for one daemon instance.
struct ApplicationConfig
{
    /// Address and port for the authenticated HTTP API.
    mw::IPSocketInfo listen_info;
    /// Telegram bot token used by the production client.
    std::string token;
    /// SQLite state database path.
    std::string db_path;
    /// Exclusive daemon lock retained for the application lifetime.
    std::unique_ptr<DatabaseLock> database_lock;
};

/// Owns the daemon components and coordinates their complete lifecycle.
class Application
{
public:
    /// Construct a daemon from validated configuration and a held lock.
    explicit Application(ApplicationConfig config);

    /// Start, run, and cleanly stop the daemon.
    int run();

private:
    std::unique_ptr<DatabaseLock> database_lock_;
    mw::IPSocketInfo listen_info_;
    std::string db_path_;
    KeyStore keys_;
    SubscriptionStore subscriptions_;
    DeliveryStore deliveries_;
    TelegramClient telegram_;
    RuntimeState state_;
    Dispatcher dispatcher_;
    Poller poller_;
    ApiServer server_;
    std::jthread signal_watcher_;
    std::atomic<bool> stopping_ = false;

    void requestStop();
    void waitForSignal(std::stop_token stop_token);
};

} // namespace telegrammer