import { EventEmitter } from 'events';
import type { TraceProcessorQueryOptions } from './traceProcessorSqlWorker';
import { type TraceProcessorLeaseMode } from './traceProcessorLeaseStore';
import type { EnterpriseRepositoryScope } from './enterpriseRepository';
export interface TraceInfo {
    id: string;
    filename: string;
    size: number;
    filePath?: string;
    uploadTime: Date;
    lastAccessTime?: Date;
    status: 'uploading' | 'processing' | 'ready' | 'error';
    error?: string;
    /** Detected trace OS — determines knowledge injection and vendor detection */
    traceOs?: 'android' | 'harmonyos' | 'unknown';
    /** Detected trace format */
    traceFormat?: 'perfetto_protobuf' | 'systrace_text' | 'atrace_text' | 'unknown';
    metadata?: {
        duration?: number;
        startTime?: number;
        endTime?: number;
        numEvents?: number;
        packages?: string[];
    };
}
export interface QueryResult {
    columns: string[];
    rows: any[][];
    durationMs: number;
    error?: string;
}
export interface TraceProcessor {
    id: string;
    traceId: string;
    status: 'initializing' | 'ready' | 'busy' | 'error';
    /** Number of in-flight queries. Used by factory to avoid evicting busy processors. */
    activeQueries: number;
    query(sql: string, options?: TraceProcessorQueryOptions): Promise<QueryResult>;
    queryRaw(body: Buffer, options?: TraceProcessorQueryOptions): Promise<Buffer>;
    destroy(): void;
}
export interface TraceProcessorLeaseQueryContext {
    traceId: string;
    leaseId: string;
    mode: TraceProcessorLeaseMode | string;
    leaseScope?: EnterpriseRepositoryScope;
}
export type TraceProcessorServiceQueryOptions = TraceProcessorQueryOptions & {
    leaseId?: string;
    leaseMode?: TraceProcessorLeaseMode | string;
    leaseScope?: EnterpriseRepositoryScope;
};
export interface TraceProcessorLeaseRestartPolicy {
    backoffMs?: number[];
    jitterMs?: number;
    sleep?: (delayMs: number) => Promise<void>;
    random?: () => number;
}
/**
 * Manages trace files and processors using the actual Perfetto Trace Processor WASM
 */
export declare class TraceProcessorService extends EventEmitter {
    private readonly leaseRestartPolicy;
    private traces;
    private processors;
    private uploads;
    private uploadDir;
    /** Guards against concurrent auto-recovery for the same trace. */
    private recoveryInProgress;
    /** Single lease supervisor per processor key; holders wait instead of retrying. */
    private leaseRestartInProgress;
    private readonly queryLeaseContext;
    constructor(uploadDir?: string, leaseRestartPolicy?: TraceProcessorLeaseRestartPolicy);
    private ensureUploadDir;
    private processorKeyForLease;
    runWithLease<T>(context: TraceProcessorLeaseQueryContext | null | undefined, fn: () => Promise<T>): Promise<T>;
    runWithLeases<T>(contexts: Array<TraceProcessorLeaseQueryContext | null | undefined>, fn: () => Promise<T>): Promise<T>;
    private resolveLeaseQueryContext;
    /**
     * Initialize a trace upload
     */
    initializeUpload(filename: string, size: number): Promise<string>;
    /**
     * Initialize a trace upload with a specific ID
     * Use this when you already have a trace ID (e.g., from a file upload)
     */
    initializeUploadWithId(traceId: string, filename: string, size: number, filePath?: string): Promise<void>;
    /**
     * Handle chunk upload for large files
     */
    uploadChunk(traceId: string, chunk: Buffer, offset: number): Promise<void>;
    /**
     * Complete the upload and start processing
     */
    completeUpload(traceId: string): Promise<void>;
    /**
     * Process the uploaded trace file
     */
    private processTrace;
    /**
     * Create a new Trace Processor instance.
     * All traces use the default Perfetto trace_processor_shell,
     * which handles both Perfetto protobuf and ftrace text formats.
     */
    private createProcessor;
    /**
     * Extract basic metadata from the trace
     */
    private extractMetadata;
    /**
     * Execute a SQL query on a trace.
     * If the processor has died (status=error), attempts to auto-recover once
     * by re-creating the processor from the on-disk trace file.
     * Concurrent callers share the same recovery promise to avoid thundering herd.
     */
    private processorForQuery;
    query(traceId: string, sql: string, options?: TraceProcessorServiceQueryOptions): Promise<QueryResult>;
    queryRaw(traceId: string, body: Buffer, options?: TraceProcessorServiceQueryOptions): Promise<Buffer>;
    /**
     * Update the last access time for a trace (called on any activity)
     * This prevents active traces from being cleaned up prematurely
     */
    touchTrace(traceId: string): void;
    /**
     * Get trace information
     */
    getTrace(traceId: string): TraceInfo | undefined;
    /**
     * Get the HTTP port of the trace processor for a given trace
     * This port can be used by the frontend to connect via HTTP RPC mode
     * Only returns port if the processor is actually ready
     */
    getProcessorPort(traceId: string): number | undefined;
    /**
     * Get trace info with processor port for frontend
     * Also updates last access time to prevent cleanup
     */
    getTraceWithPort(traceId: string): (TraceInfo & {
        port?: number;
        processor?: {
            status: string;
        };
    }) | undefined;
    getTraceWithLeasePort(traceId: string, leaseId: string, mode: TraceProcessorLeaseMode | string): (TraceInfo & {
        port?: number;
        processor?: {
            status: string;
        };
    }) | undefined;
    /**
     * Register an external RPC connection (frontend already connected to trace_processor)
     * This allows AI analysis to work with traces loaded via external HTTP RPC
     * @param traceId - A generated trace ID for this external connection
     * @param port - The port number where trace_processor is running
     * @param traceName - Display name for the trace
     */
    registerExternalRpc(traceId: string, port: number, traceName: string): Promise<void>;
    /**
     * Load trace from disk if it exists but is not in memory
     * This is useful after server restart when traces are on disk but not loaded
     */
    loadTraceFromDisk(traceId: string): Promise<TraceInfo | undefined>;
    /**
     * Get or load trace - checks memory first, then tries to load from disk
     */
    getOrLoadTrace(traceId: string): Promise<TraceInfo | undefined>;
    ensureProcessorForLease(traceId: string, leaseId: string, mode: TraceProcessorLeaseMode | string, leaseScope?: EnterpriseRepositoryScope): Promise<TraceProcessor>;
    restartLease(traceId: string, leaseId: string, mode: TraceProcessorLeaseMode | string, leaseScope: EnterpriseRepositoryScope): Promise<TraceProcessor>;
    private restartLeaseProcessor;
    private runLeaseRestartSupervisor;
    private restartBackoffDelayMs;
    private restartSleep;
    private destroyProcessorForRestart;
    private markLeaseCrashedForRestart;
    private markLeaseRestarting;
    private markLeaseReadyAfterRestart;
    private markLeaseFailedAfterRestart;
    /**
     * Get all traces
     */
    getAllTraces(): TraceInfo[];
    /**
     * Delete a trace
     */
    deleteTrace(traceId: string): Promise<void>;
    cleanupProcessorsForTraces(traceIds: Iterable<string>): number;
    /**
     * Load a trace directly from a file path (for CLI/testing use)
     * This copies the file to the upload directory and processes it
     */
    loadTraceFromFilePath(filePath: string): Promise<string>;
    /**
     * Get file path for a trace.
     *
     * NOTE: public so that scene-reconstruction's traceHash + report-store
     * code paths can hash the on-disk content. Existence of the file at the
     * returned path is also the source of truth for "is this trace
     * file-backed or external RPC".
     */
    getTraceFilePath(traceId: string): string;
    /**
     * Cleanup old traces with smart activity detection
     *
     * A trace is only cleaned up when BOTH conditions are met:
     * 1. Upload time exceeds maxAge (how old the trace is)
     * 2. Last access time exceeds idleTimeout (how long since last activity)
     *
     * This prevents active traces from being cleaned up prematurely while
     * still cleaning up truly abandoned traces.
     *
     * @param maxAge - Maximum age since upload before trace becomes eligible for cleanup (default: 2 hours)
     * @param idleTimeout - Minimum idle time (no queries) before trace can be cleaned (default: 30 minutes)
     */
    cleanup(maxAge?: number, // 2 hours since upload
    idleTimeout?: number): Promise<void>;
    /**
     * Check if a trace is considered active (recently accessed)
     */
    isTraceActive(traceId: string, idleTimeout?: number): boolean;
}
export declare function getTraceProcessorService(): TraceProcessorService;
export declare function setTraceProcessorServiceForTests(service: TraceProcessorService | null): void;
//# sourceMappingURL=traceProcessorService.d.ts.map