/**
 * detect-remote-backend.ts
 *
 * Answers one question for the wholesale-artifact-loss guard
 * (`W-detect-wholesale-artifact-loss`): was a *remote* artifact backend
 * (GCS-direct or API-Gateway) wired for this run?
 *
 * The signal can't come from the manifest — a wholesale upload failure leaves
 * every section `store: "local"`, which is byte-for-byte what a legitimate
 * local-only run produces. So the detector reads it from the actual writer
 * wiring instead. The composition root layers a remote writer under a
 * `FanoutArtifactWriter([remote, local])` when (and only when) credentials are
 * present; this walks the decorator chain to find that fanout's remote leg.
 *
 * Walking (rather than threading a boolean through `PipelineState`) keeps the
 * signal anchored to the real wiring and mirrors `findAccumulator` in
 * `finalize-run-step.ts`.
 */
import { AccumulatingArtifactWriter } from "./accumulating-artifact-writer.js";
import { ApiGatewayArtifactWriter } from "./api-gateway-artifact-writer.js";
import { BatchingApiGatewayArtifactWriter } from "./batching-api-gateway-artifact-writer.js";
import { FanoutArtifactWriter } from "./fanout-artifact-writer.js";
import { GcsArtifactWriter } from "./gcs-artifact-writer.js";
import { InstrumentedArtifactWriter } from "./instrumented-artifact-writer.js";
/** Safety belt against a future decorator chain accidentally cycling. */
const MAX_DEPTH = 8;
/** A writer that physically uploads to a cross-machine-readable store. */
function isRemoteWriter(writer) {
    return (writer instanceof GcsArtifactWriter ||
        writer instanceof ApiGatewayArtifactWriter ||
        writer instanceof BatchingApiGatewayArtifactWriter);
}
/**
 * Walk a writer's decorator chain and report whether a remote backend is
 * reachable. Unwraps `InstrumentedArtifactWriter` / `AccumulatingArtifactWriter`
 * decorators and descends into a `FanoutArtifactWriter`'s delegates. Returns
 * `false` for a local-only or no-op writer.
 */
export function hasRemoteArtifactBackend(writer) {
    let cursor = writer;
    for (let depth = 0; cursor && depth < MAX_DEPTH; depth++) {
        if (cursor instanceof FanoutArtifactWriter) {
            return cursor.delegates.some((d) => isRemoteWriter(d));
        }
        if (cursor instanceof InstrumentedArtifactWriter ||
            cursor instanceof AccumulatingArtifactWriter) {
            cursor = cursor.inner;
            continue;
        }
        // A bare writer — either a remote writer used directly, or a local/no-op
        // writer (the local-only default).
        return isRemoteWriter(cursor);
    }
    return false;
}
