/**
 * Default Perfetto profiler configuration
 */
export const DEFAULT_PERFETTO_CONFIG = {
    includeStackTraces: false,
};
/**
 * A performance profiler that outputs Chrome Trace Event JSON format
 * compatible with Perfetto UI and chrome://tracing
 */
export class PerfettoProfiler {
    events = [];
    activeEvents = new Map();
    tracks = new Map();
    nextTrackId = 1;
    sessionStartTime;
    config;
    constructor(config = {}) {
        this.config = { ...DEFAULT_PERFETTO_CONFIG, ...config };
        this.sessionStartTime = this.getTimestamp();
        // Create main track for high-level operations
        this.createTrack("main", "Clark AI Session", "main");
    }
    getTimestamp() {
        return performance.now() * 1000; // Convert ms to μs
    }
    /**
     * Create or get a track for organizing events
     */
    createTrack(trackKey, trackName, type) {
        if (this.tracks.has(trackKey)) {
            return this.tracks.get(trackKey).id;
        }
        const track = {
            id: this.nextTrackId++,
            name: trackName,
            type,
        };
        this.tracks.set(trackKey, track);
        return track.id;
    }
    getTrackId(trackKey, trackName, type = "tool") {
        if (this.tracks.has(trackKey)) {
            return this.tracks.get(trackKey).id;
        }
        return this.createTrack(trackKey, trackName || trackKey, type);
    }
    /**
     * Start timing a new event
     */
    startFrame(frameName, trackKey, args) {
        const timestamp = this.getTimestamp();
        const pid = 1; // Single process for now
        const tid = trackKey
            ? this.getTrackId(trackKey, frameName)
            : this.getTrackId("main", "Main", "main");
        const eventKey = `${trackKey || "main"}:${frameName}:${timestamp}`;
        const activeEvent = {
            name: frameName,
            startTime: timestamp,
            pid,
            tid,
            args,
        };
        this.activeEvents.set(eventKey, activeEvent);
    }
    /**
     * Update the args of the most recent active event for a track
     */
    updateActiveFrameArgs(trackKey, additionalArgs) {
        const targetTrack = trackKey || "main";
        // Find the most recent event for this track
        let mostRecentKey = null;
        let mostRecentTime = 0;
        for (const [key, event] of this.activeEvents.entries()) {
            if (key.startsWith(`${targetTrack}:`)) {
                if (event.startTime > mostRecentTime) {
                    mostRecentTime = event.startTime;
                    mostRecentKey = key;
                }
            }
        }
        if (mostRecentKey && additionalArgs) {
            const activeEvent = this.activeEvents.get(mostRecentKey);
            activeEvent.args = { ...activeEvent.args, ...additionalArgs };
        }
    }
    /**
     * End timing the most recent event for a track
     */
    endFrame(trackKey) {
        const targetTrack = trackKey || "main";
        // Find the most recent event for this track
        let mostRecentKey = null;
        let mostRecentTime = 0;
        for (const [key, event] of this.activeEvents.entries()) {
            if (key.startsWith(`${targetTrack}:`)) {
                if (event.startTime > mostRecentTime) {
                    mostRecentTime = event.startTime;
                    mostRecentKey = key;
                }
            }
        }
        if (!mostRecentKey) {
            // Only warn if we actually expected to find an event
            // Silently ignore if no active events (this is normal in many cases)
            return;
        }
        const activeEvent = this.activeEvents.get(mostRecentKey);
        const endTime = this.getTimestamp();
        const duration = endTime - activeEvent.startTime;
        // Create complete event
        const traceEvent = {
            name: activeEvent.name,
            ph: "X",
            ts: activeEvent.startTime,
            dur: duration,
            pid: activeEvent.pid,
            tid: activeEvent.tid,
            args: activeEvent.args,
        };
        this.events.push(traceEvent);
        this.activeEvents.delete(mostRecentKey);
    }
    /**
     * Time a function execution with automatic start/end
     */
    async timeAsync(frameName, fn, trackKey, args) {
        this.startFrame(frameName, trackKey, args);
        try {
            return await fn();
        }
        finally {
            this.endFrame(trackKey);
        }
    }
    /**
     * Time a synchronous function execution with automatic start/end
     */
    timeSync(frameName, fn, trackKey, args) {
        this.startFrame(frameName, trackKey, args);
        try {
            return fn();
        }
        finally {
            this.endFrame(trackKey);
        }
    }
    /**
     * Add an instant event (single point in time)
     */
    addInstantEvent(name, trackKey, args) {
        const timestamp = this.getTimestamp();
        const pid = 1;
        const tid = trackKey ? this.getTrackId(trackKey) : this.getTrackId("main");
        const event = {
            name,
            ph: "I",
            ts: timestamp,
            pid,
            tid,
            args,
        };
        this.events.push(event);
    }
    /**
     * End all active events across all tracks
     */
    endAllActiveEvents() {
        const remainingEvents = Array.from(this.activeEvents.keys());
        for (const key of remainingEvents) {
            const trackKey = key.split(":")[0];
            this.endFrame(trackKey);
        }
    }
    /**
     * Generate the complete Perfetto trace JSON
     */
    generateTrace() {
        // End any remaining active events
        this.endAllActiveEvents();
        // Add track name events for better visualization
        const trackEvents = [];
        for (const [_trackKey, track] of this.tracks.entries()) {
            if (track.id !== this.getTrackId("main")) {
                trackEvents.push({
                    name: "thread_name",
                    ph: "M",
                    ts: this.sessionStartTime,
                    pid: 1,
                    tid: track.id,
                    args: { name: track.name },
                });
            }
        }
        return {
            traceEvents: [...trackEvents, ...this.events],
            metadata: {
                clockSync: "microseconds",
                traceConfig: this.config,
                generatedAt: new Date().toISOString(),
            },
        };
    }
    /**
     * Generate JSON string of the trace
     */
    generateJSON() {
        const trace = this.generateTrace();
        return JSON.stringify(trace, null, 2);
    }
    reset() {
        this.events = [];
        this.activeEvents.clear();
        this.tracks.clear();
        this.nextTrackId = 1;
        this.sessionStartTime = this.getTimestamp();
        // Recreate main track
        this.createTrack("main", "Clark AI Session", "main");
    }
    /**
     * Get current statistics
     */
    getStats() {
        return {
            totalEvents: this.events.length,
            activeEvents: this.activeEvents.size,
            totalTracks: this.tracks.size,
        };
    }
    updateConfig(config) {
        this.config = { ...this.config, ...config };
    }
    getTracks() {
        return new Map(this.tracks);
    }
}
// Global Perfetto profiler instance
export const globalPerfettoProfiler = new PerfettoProfiler();
//# sourceMappingURL=perfetto-profiler.js.map