BareGit
#pragma once

#include <cstdint>

#include <mw/crypto.hpp>
#include <mw/error.hpp>

#include "card_pool.h"
#include "clock.h"
#include "data.h"

/// Result of one successful atomic card pull.
struct PullResult
{
    /// Selected current card.
    Card card;

    /// User's quantity after the award.
    std::int64_t quantity;
};

/// Own lazy pull accrual and atomic collection awards.
class CollectionService
{
public:
    /// Construct the service over injected time, randomness, and persistence.
    CollectionService(
        DataSourceInterface& data_source,
        ClockInterface& clock,
        mw::CryptoInterface& crypto,
        std::uint32_t maximum_accumulated_pulls);

    /// Refresh and persist one user's available pulls.
    mw::E<User> refresh(std::int64_t user_id);

    /// Consume one pull and increment the selected holding atomically.
    mw::E<PullResult> pull(std::int64_t user_id);

private:
    /// Calculate availability and nondecreasing refresh day.
    std::pair<std::uint32_t, std::int64_t> effectivePullState(
        const User& user, std::int64_t current_day) const;

    DataSourceInterface& data_source_;
    ClockInterface& clock_;
    mw::CryptoInterface& crypto_;
    std::uint32_t maximum_accumulated_pulls_;
    CardPoolService card_pool_;
};