BareGit
#pragma once

#include <cstdint>
#include <optional>
#include <string>
#include <vector>

#include <nlohmann/json.hpp>
#include <mw/error.hpp>

namespace telegrammer
{

/// JSON representation used at Telegram and callback boundaries.
using json = nlohmann::json;

/// Describes one durable callback attempt and its operator-visible metadata.
struct DeliveryJob
{
    /// Database identifier for the delivery row.
    int64_t id;
    /// Telegram bot identity associated with the row.
    int64_t bot_id;
    /// Subscription that owns the callback.
    int64_t subscription_id;
    /// Telegram update identifier used for deduplication.
    int64_t update_id;
    /// Number of attempts already claimed, including the current claim.
    int attempt_count;
    /// Wall-clock time at which the next attempt may run.
    int64_t next_attempt_at;
    /// Wall-clock time at which the delivery was first queued.
    int64_t created_at;
    /// Sanitized failure reason retained for dead-letter inspection.
    std::string last_error;
    /// Callback destination for an active delivery.
    std::string callback_url;
    /// Original Telegram Message JSON for an active delivery.
    std::string payload;
};

/// Owns the polling cursor, username observations, and callback queue.
class DeliveryStore
{
public:
    /// Construct a delivery store backed by the supplied SQLite database.
    explicit DeliveryStore(std::string db_path);

    /// Bind the database to one Telegram bot identity.
    mw::E<void> ensureBot(int64_t bot_id) const;

    /// Read the next persistent polling offset for the configured bot.
    mw::E<int64_t> offset(int64_t bot_id) const;

    /// Atomically ingest one validated Telegram update batch.
    mw::E<void> ingest(int64_t bot_id, const json& updates) const;

    /// Resolve a recently observed private-chat username.
    mw::E<std::optional<int64_t>> resolveUsername(
        const std::string& username) const;

    /// Claim the oldest eligible callback job for one worker.
    mw::E<std::optional<DeliveryJob>> claimNext() const;

    /// Delete a successfully delivered job.
    mw::E<void> complete(int64_t delivery_id) const;

    /// Retry or dead-letter a failed callback attempt.
    mw::E<void> fail(int64_t delivery_id, const std::string& error,
                     bool retryable, std::optional<int> retry_after) const;

    /// Return in-flight jobs to the pending state after a restart.
    mw::E<void> resetInFlight() const;

    /// Return the total number of retained delivery rows.
    mw::E<int64_t> count() const;

    /// List retained dead-letter jobs for operator inspection.
    mw::E<std::vector<DeliveryJob>> listDead() const;

    /// Reset one dead-letter job for another delivery attempt.
    mw::E<bool> retry(int64_t delivery_id) const;

    /// Delete one dead-letter job.
    mw::E<bool> deleteDead(int64_t delivery_id) const;

    /// Purge dead-letter jobs older than the retention period.
    mw::E<int64_t> purgeExpiredDead() const;

private:
    std::string db_path_;
};

} // namespace telegrammer