import { StreamEventBus } from "./event-bus.js";
export class StreamSession {
    id;
    startTime;
    events;
    config;
    organizationId;
    applicationId;
    getJwt;
    getAttributes;
    attempt = 1;
    providerAttempt = 1;
    provider;
    metrics = {
        chunkCount: 0,
        totalTokens: 0,
        retryCount: 0,
        totalRetryDelayMs: 0,
        durationMs: 0,
        timeToFirstTokenMs: undefined,
    };
    error = null;
    outcome = "pending";
    // tracks when we last received a chunk or started a retry, used for max-time checks.
    lastActivityTime;
    constructor(options) {
        this.id = crypto.randomUUID();
        this.startTime = Date.now();
        this.lastActivityTime = this.startTime;
        this.config = options.config;
        this.provider = options.initialProvider;
        this.organizationId = options.organizationId;
        this.applicationId = options.applicationId;
        this.getJwt = options.getJwt;
        this.getAttributes = options.getAttributes;
        this.events = new StreamEventBus();
    }
    /**
     * Finalize the session with an outcome.
     *
     * Can only be called once. Subsequent calls are ignored.
     * Emits the appropriate lifecycle event based on outcome.
     *
     * @param outcome - The final outcome of the session
     * @param error - Optional error that caused failure
     */
    finalize(outcome, error) {
        if (this.outcome !== "pending") {
            return;
        }
        this.outcome = outcome;
        this.error = error ?? null;
        this.metrics.durationMs = Date.now() - this.startTime;
        switch (outcome) {
            case "complete":
                void this.events.emit("session:complete", this);
                break;
            case "error":
                void this.events.emit("session:error", error, this);
                break;
            case "aborted":
                void this.events.emit("session:abort", this);
                break;
        }
    }
    recordRetry(delayMs) {
        this.attempt++;
        this.providerAttempt++;
        this.metrics.retryCount++;
        this.metrics.totalRetryDelayMs += delayMs;
        this.lastActivityTime = Date.now();
    }
    resetAttempts() {
        this.attempt = 0;
        this.providerAttempt = 0;
    }
    resetProviderAttempts() {
        this.providerAttempt = 0;
    }
    recordChunk() {
        if (this.metrics.chunkCount === 0) {
            this.metrics.timeToFirstTokenMs = Date.now() - this.startTime;
        }
        this.metrics.chunkCount++;
        this.lastActivityTime = Date.now();
    }
    setTotalTokens(tokens) {
        this.metrics.totalTokens = tokens;
    }
    isPending() {
        return this.outcome === "pending";
    }
    getElapsedMs() {
        return Date.now() - this.startTime;
    }
    // use this for max-time checks, NOT getElapsedMs(). we only want to timeout
    // if nothing is happening, not if the stream has been running for a while.
    getTimeSinceLastActivity() {
        return Date.now() - this.lastActivityTime;
    }
    resetActivityTimer() {
        this.lastActivityTime = Date.now();
    }
}
//# sourceMappingURL=session.js.map