/**
 * InstrumentedArtifactWriter — decorator for W0056 spike instrumentation.
 *
 * Wraps any `ArtifactWriter` and records end-to-end `emit` / `appendNdjson` /
 * `writeManifest` durations into an `UploadMetrics` sink. The writer-internal
 * phase timings (sign vs. PUT, compose groups) are recorded by the concrete
 * writers; this decorator records the caller-observed totals so the summary
 * shows both views.
 *
 * Triggers `UploadMetrics.summarize()` from `writeManifest` (after delegation)
 * — that is the natural end-of-run signal and avoids a separate lifecycle
 * hook in the composition root.
 */
export class InstrumentedArtifactWriter {
    /**
     * Exposed so `FinalizeRunStep` can walk decorator chains to reach the
     * underlying `AccumulatingArtifactWriter` when `AILF_UPLOAD_METRICS=1`
     * (which wraps the accumulator in this decorator). Mirrors the
     * analogous field on `AccumulatingArtifactWriter`. Treat as read-only.
     */
    inner;
    metrics;
    writerName;
    constructor(inner, metrics) {
        this.inner = inner;
        this.metrics = metrics;
        this.writerName = inner.constructor.name;
    }
    async emit(type, association, payload) {
        const start = Date.now();
        let success = false;
        try {
            const ref = await this.inner.emit(type, association, payload);
            success = ref !== null;
            this.metrics.record({
                phase: "emit",
                writer: this.writerName,
                type,
                ms: Date.now() - start,
                bytes: ref?.bytes,
                success,
            });
            return ref;
        }
        catch (err) {
            this.metrics.record({
                phase: "emit",
                writer: this.writerName,
                type,
                ms: Date.now() - start,
                success: false,
            });
            throw err;
        }
    }
    async appendNdjson(type, association, rows) {
        const start = Date.now();
        try {
            const ref = await this.inner.appendNdjson(type, association, rows);
            this.metrics.record({
                phase: "ndjson-part",
                writer: this.writerName,
                type,
                ms: Date.now() - start,
                bytes: ref?.bytes,
                success: ref !== null,
            });
            return ref;
        }
        catch (err) {
            this.metrics.record({
                phase: "ndjson-part",
                writer: this.writerName,
                type,
                ms: Date.now() - start,
                success: false,
            });
            throw err;
        }
    }
    async writeManifest(runId, manifest) {
        const start = Date.now();
        let ref = null;
        try {
            ref = await this.inner.writeManifest(runId, manifest);
            this.metrics.record({
                phase: "manifest",
                writer: this.writerName,
                type: "manifest",
                ms: Date.now() - start,
                bytes: ref?.bytes,
                success: ref !== null,
            });
            return ref;
        }
        finally {
            // Summarize once, after the manifest write resolves, regardless of outcome.
            await this.metrics.summarize();
        }
    }
    async writeBulk(type, runId, data) {
        const start = Date.now();
        try {
            const ref = await this.inner.writeBulk(type, runId, data);
            this.metrics.record({
                phase: "emit",
                writer: this.writerName,
                type,
                ms: Date.now() - start,
                bytes: ref?.bytes,
                success: ref !== null,
            });
            return ref;
        }
        catch (err) {
            this.metrics.record({
                phase: "emit",
                writer: this.writerName,
                type,
                ms: Date.now() - start,
                success: false,
            });
            throw err;
        }
    }
    async writePerEntry(type, runId, entries) {
        const start = Date.now();
        try {
            const ref = await this.inner.writePerEntry(type, runId, entries);
            this.metrics.record({
                phase: "emit",
                writer: this.writerName,
                type,
                ms: Date.now() - start,
                bytes: ref?.bytes,
                success: ref !== null,
            });
            return ref;
        }
        catch (err) {
            this.metrics.record({
                phase: "emit",
                writer: this.writerName,
                type,
                ms: Date.now() - start,
                success: false,
            });
            throw err;
        }
    }
}
