#include "core/tracking/tracking_authority.h"

namespace reasampler::tracking {

ProtectionAnswer pruneProtection(const TrackingState& state) {
    ProtectionAnswer answer;

    // heldPaths is taken unconditionally: on an abort the usage fold returns its
    // protect-all set, which is the widest (safest) answer available.
    answer.heldPaths = state.usage.heldPaths;

    if (state.usage.abortPrune) {
        answer.blocked = true;
        answer.unreadableUsageKeys = state.usage.offendingKeys;
    }

    if (ledgerDegraded(state.ledgerStatus)) {
        answer.blocked = true;
        answer.ledgerUnreadable = state.ledgerStatus == LedgerStatus::Unreadable;
        answer.ledgerFutureVersion = state.ledgerStatus == LedgerStatus::FutureVersion;
    }

    // Populated only on a clean answer: on ANY block an empty `owned` makes
    // (owned ∩ present) empty, so even a caller that ignored `blocked` deletes nothing.
    if (!answer.blocked) answer.ownedPaths = state.ledger.ownedPaths();
    return answer;
}

Answer tiedUsageExists(const TrackingState& state, const std::string& capturePath,
                       const std::string& ownUsageKey) {
    if (capturePath.empty()) return Answer::Indeterminate;
    if (ledgerDegraded(state.ledgerStatus)) return Answer::Indeterminate;
    if (state.usage.abortPrune) return Answer::Indeterminate;

    for (const wire::CountedUsage& counted : state.usage.counted) {
        const bool isOwn = !ownUsageKey.empty() && counted.key == ownUsageKey &&
                           !counted.record.unioned;
        if (isOwn) continue;
        for (const wire::UsageHold& hold : counted.record.holds)
            if (hold.relativePath == capturePath) return Answer::Yes;
    }
    return Answer::No;
}

Landing resampleLanding(Answer answer) {
    return answer == Answer::No ? Landing::Replace : Landing::AddDistinct;
}

}  // namespace reasampler::tracking
