#pragma once
// tracking_authority — the ONE place the two safety-critical consumers are answered:
// prune's protected set and the resample's replace-vs-add decision. Both read the
// same TrackingState, so they cannot drift apart; every unreadable or ambiguous
// input resolves to the non-destructive side of its own question.

#include <string>
#include <vector>

#include "core/tracking/origin_ledger.h"
#include "core/wire/sample_usage.h"

namespace reasampler::tracking {

// A borrowed view of everything both consumers read, gathered once by the shell.
// References, not values: the ledger can hold thousands of records and both answers
// are computed from one gather. Never outlives the gather that built it.
struct TrackingState {
    LedgerStatus                 ledgerStatus;
    const OriginLedger&          ledger;
    const wire::UsageFoldResult& usage;
};

// Prune's answer. `blocked` means the protected set is unknowable and the prune must
// HALT — deleting with degraded protection is the data-loss direction. The two
// blocker fields say what to tell the operator; the caller composes the message
// (the pure core does not know ext-state key spellings).
//
// Belt-and-braces on ANY block, whichever side blocked: heldPaths still carries the
// usage fold's protect-all set, and ownedPaths is left EMPTY — so a caller that
// ignored `blocked` still computes an empty orphan set rather than deleting.
struct ProtectionAnswer {
    bool blocked = false;
    bool ledgerUnreadable = false;    // corrupt blob — repairable by clearing the key
    bool ledgerFutureVersion = false; // written by a newer build — must NOT be cleared
    std::vector<std::string> unreadableUsageKeys;
    std::vector<std::string> heldPaths;   // union into prune's `referenced`
    std::vector<std::string> ownedPaths;  // prune's `owned`
};

ProtectionAnswer pruneProtection(const TrackingState& state);

// The resample's answer, per capture. `Indeterminate` is not a failure to compute —
// it is the recorded verdict that the state could not be read, and the caller must
// treat it exactly as `Yes` (never take the replace branch).
enum class Answer { No, Yes, Indeterminate };

// Does a usage tied to `capturePath` exist, other than the asking instance's own?
//
//   * degraded ledger, or any unreadable usage record -> Indeterminate.
//   * otherwise Yes iff some counting live record holds the path.
//
// `ownUsageKey` is the asking instance's own "rsusage_<guid>" key, excluded from the
// scan so a bake does not see itself; empty counts every holder. A `unioned` record
// is never excluded.
//
// Never-recorded (no ledger record for the path) is a definite answer, not an
// abstention: a pre-existing capture nothing holds answers No.
//
// The universes cannot disagree: a Yes implies `capturePath` is in the same
// pruneProtection(state).heldPaths, which is itself a subset of what prune protects.
Answer tiedUsageExists(const TrackingState& state, const std::string& capturePath,
                       const std::string& ownUsageKey);

// What a resample does with its result: take over the source's bank entry, or land beside
// it as a new one.
enum class Landing { Replace, AddDistinct };

// Replace only on a definite No. `Indeterminate` takes the same branch as `Yes` because
// AddDistinct disturbs no existing holder — it is the non-destructive side of this
// question, which is the rule the whole directory is written to.
Landing resampleLanding(Answer answer);

}  // namespace reasampler::tracking
