import { ShortcutClientLogContextStore } from './context.js';
import { SHORTCUT_CLIENT_LOG_SOURCE } from './types.js';
function omitUndefined(input) {
    return Object.fromEntries(Object.entries(input).filter(([, value]) => value !== undefined));
}
/**
 * Runtime-owned client logger for ShortcutXL observability.
 *
 * This package intentionally knows nothing about PostHog, browser super properties,
 * or compatibility with unrelated clients. It owns one contract only:
 * batched client-shortcutxl log rows sent to /api/logs.
 */
export class ShortcutClientLogger {
    transport;
    context;
    flushIntervalMs;
    maxBufferSize;
    now;
    setIntervalFn;
    clearIntervalFn;
    buffer = [];
    flushTimer = null;
    pendingFlush = null;
    destroyed = false;
    enabled = true;
    constructor(options) {
        this.transport = options.transport;
        this.context = options.context ?? new ShortcutClientLogContextStore();
        this.flushIntervalMs = options.flushIntervalMs ?? 5000;
        this.maxBufferSize = options.maxBufferSize ?? 50;
        this.now = options.now ?? (() => new Date());
        this.setIntervalFn = options.setIntervalFn ?? setInterval;
        this.clearIntervalFn = options.clearIntervalFn ?? clearInterval;
    }
    setUserId(userId) {
        this.context.setUserId(userId);
    }
    clearUserId() {
        this.context.clearUserId();
    }
    setUserContext(input) {
        this.context.setUserContext(input);
    }
    clearUserContext() {
        this.context.clearUserContext();
    }
    setSessionId(sessionId) {
        this.context.setSessionId(sessionId);
    }
    clearSessionId() {
        this.context.clearSessionId();
    }
    setBuildInfo(input) {
        this.context.setBuildInfo(input);
    }
    setEnabled(enabled) {
        this.enabled = enabled;
        if (!enabled && this.flushTimer) {
            this.clearIntervalFn(this.flushTimer);
            this.flushTimer = null;
        }
    }
    disable() {
        this.setEnabled(false);
        return this.flush();
    }
    info(input) {
        this.emit('info', input);
    }
    warn(input) {
        this.emit('warn', input);
    }
    error(input) {
        this.emit('error', input);
    }
    emit(level, input) {
        if (this.destroyed || !this.enabled)
            return;
        if (!this.flushTimer) {
            this.startPeriodicFlush();
        }
        const timestamp = this.now().toISOString();
        const snapshot = this.context.getSnapshot();
        const entry = omitUndefined({
            source: SHORTCUT_CLIENT_LOG_SOURCE,
            level,
            event: input.event,
            module: input.module,
            created_at: timestamp,
            analytics_event: input.analyticsEvent || undefined,
            duration: input.duration,
            data: input.data,
            ...snapshot
        });
        this.buffer.push(entry);
        if (this.buffer.length >= this.maxBufferSize) {
            void this.flush();
        }
    }
    startPeriodicFlush() {
        this.flushTimer = this.setIntervalFn(() => {
            void this.flush();
        }, this.flushIntervalMs);
    }
    async flush() {
        if (this.pendingFlush) {
            await this.pendingFlush;
            return;
        }
        if (this.buffer.length === 0) {
            return;
        }
        const batch = {
            client_time: this.now().toISOString(),
            entries: this.buffer
        };
        this.buffer = [];
        this.pendingFlush = this.transport
            .send(batch)
            .catch(() => {
            // Fail open. Observability must never break the primary user flow.
        })
            .finally(() => {
            this.pendingFlush = null;
        });
        await this.pendingFlush;
    }
    async destroy() {
        this.destroyed = true;
        this.setEnabled(false);
        await this.flush();
    }
}
//# sourceMappingURL=client-logger.js.map