#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