"use strict";
/**
 * Copyright: (c) Myia SAS 2026.
 * This file and its contents are licensed under the AGPLv3 License.
 * Please see the LICENSE file at the root of this repository
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.TraceEventRecorder = exports.SCHEMA_VERSION = void 0;
const active_enter_stack_1 = require("./active-enter-stack");
const trace_schema_1 = require("../model/trace-schema");
Object.defineProperty(exports, "SCHEMA_VERSION", { enumerable: true, get: function () { return trace_schema_1.SCHEMA_VERSION; } });
const enter_event_builder_1 = require("./event-builders/enter-event-builder");
const ok_event_builder_1 = require("./event-builders/ok-event-builder");
const throw_event_builder_1 = require("./event-builders/throw-event-builder");
const meta_event_builder_1 = require("./event-builders/meta-event-builder");
class TraceEventRecorder {
    constructor(options) {
        this.SCHEMA_VERSION = trace_schema_1.SCHEMA_VERSION;
        this.dynamicContext = null;
        this.currentPage = null;
        this.enterStack = new active_enter_stack_1.ActiveEnterStack();
        this.stepStack = [];
        this.seq = 0;
        /**
         * Swap the active exporter for subsequent events. Used by the fixture
         * to install a fresh projector+tee at the start of every test —
         * that way each test has an isolated output pipeline without the
         * recorder having to be rebuilt. The caller is responsible for
         * flushing/closing the previous exporter if needed.
         */
        this.setExporter = (newExporter) => {
            this.exporter = newExporter;
        };
        this.reset = () => {
            this.exporter.clear();
            this.enterStack.clear();
            this.seq = 0;
            this.startedAt = this.clock.now();
            (0, meta_event_builder_1.buildMetaEvent)(this);
        };
        this.setContext = (ctx) => {
            this.dynamicContext = ctx ?? null;
        };
        this.setPage = (page) => {
            this.currentPage = page ?? null;
        };
        this.pushStep = (name) => {
            this.stepStack.push(name);
        };
        this.popStep = () => {
            this.stepStack.pop();
        };
        /**
         * Stamp a highlight screenshot filename onto whatever enter event
         * is currently on top of the active-enter stack. Called by the
         * locator-screenshots feature right after it writes the PNG to
         * disk. No-op if the stack is empty (screenshot fired outside any
         * instrumented statement, e.g. before the first __enter).
         */
        this.setCurrentStatementScreenshot = (filename) => {
            const top = this.enterStack.peek();
            if (top)
                top.screenshot = filename;
        };
        /**
         * Read the `seq` of the enter event currently on top of the active
         * stack — i.e. "what statement is running right now" — for sidecar
         * adapters (network, console) that need to attribute an out-of-band
         * event back to a statement. Returns `undefined` when the stack is
         * empty (event fired between statements / outside any test body).
         *
         * Pure read; no allocation, safe to call from a Playwright event
         * listener on the hot path.
         */
        this.getCurrentStatementSeq = () => {
            return this.enterStack.peek()?.seq;
        };
        /**
         * Snapshot the currently-active step path (a copy of the step
         * stack) for sidecar records that want to denormalize the path the
         * way `StatementProjector` does. Returns `undefined` when no
         * `test.step(...)` is active so callers can omit the field
         * entirely instead of writing an empty array.
         */
        this.getCurrentStepPath = () => {
            if (this.stepStack.length === 0)
                return undefined;
            return this.stepStack.slice();
        };
        /**
         * The wall-clock origin used by every timestamp in the trace —
         * sidecar adapters subtract this from `clock.now()` to produce a
         * `t` field on the same axis as `Statement.t`.
         */
        this.getStartedAt = () => {
            return this.startedAt;
        };
        this.__enter = (meta) => {
            (0, enter_event_builder_1.buildEnterEvent)(this, meta);
        };
        this.__ok = (vars) => {
            (0, ok_event_builder_1.buildOkEvent)(this, vars);
        };
        this.__throw = (err) => {
            (0, throw_event_builder_1.buildThrowEvent)(this, err);
        };
        this.exporter = options.exporter;
        this.clock = options.clock;
        this.staticContext = options.staticContext ?? {};
        this.startedAt = this.clock.now();
    }
}
exports.TraceEventRecorder = TraceEventRecorder;
