/**
 * @plan PLAN-20250120-DEBUGLOGGING.P10
 * @requirement REQ-005
 */
import { promises as fs } from 'fs';
import { join } from 'path';
import { homedir } from 'os';
import { LLXPRT_DIR } from '../utils/paths.js';
export class FileOutput {
    static instance;
    debugDir;
    currentLogFile;
    writeQueue = [];
    isWriting = false;
    disposed = false;
    flushTimeout = null;
    maxFileSize = 10 * 1024 * 1024; // 10MB
    maxQueueSize = 1000;
    batchSize = 50;
    flushInterval = 1000; // 1 second
    constructor() {
        const home = homedir();
        // Handle test environments where homedir might not be available
        this.debugDir = home
            ? join(home, LLXPRT_DIR, 'debug')
            : join(process.cwd(), LLXPRT_DIR, 'debug');
        this.currentLogFile = this.generateLogFileName();
        this.startFlushTimer();
    }
    static getInstance() {
        if (!FileOutput.instance) {
            FileOutput.instance = new FileOutput();
        }
        return FileOutput.instance;
    }
    async write(entry) {
        if (this.disposed) {
            return;
        }
        // Add to queue
        this.writeQueue.push({
            entry,
            timestamp: Date.now(),
        });
        // Prevent queue from growing too large
        if (this.writeQueue.length > this.maxQueueSize) {
            this.writeQueue = this.writeQueue.slice(-this.maxQueueSize);
        }
        // Flush immediately if queue is large or not currently writing
        if (this.writeQueue.length >= this.batchSize || !this.isWriting) {
            await this.flushQueue();
        }
    }
    async dispose() {
        this.disposed = true;
        if (this.flushTimeout) {
            clearTimeout(this.flushTimeout);
            this.flushTimeout = null;
        }
        // Flush any remaining entries
        await this.flushQueue();
    }
    startFlushTimer() {
        if (this.disposed) {
            return;
        }
        this.flushTimeout = setTimeout(async () => {
            await this.flushQueue();
            this.startFlushTimer();
        }, this.flushInterval);
    }
    async flushQueue() {
        if (this.isWriting || this.writeQueue.length === 0 || this.disposed) {
            return;
        }
        this.isWriting = true;
        let entriesToWrite = [];
        try {
            await this.ensureDirectoryExists();
            await this.checkFileRotation();
            // Process entries in batches
            entriesToWrite = this.writeQueue.splice(0, this.batchSize);
            if (entriesToWrite.length === 0) {
                return;
            }
            // Convert to JSONL format
            const jsonlData = entriesToWrite.map(({ entry }) => JSON.stringify(entry)).join('\n') +
                '\n';
            // Write to file with proper permissions
            await fs.appendFile(this.currentLogFile, jsonlData, {
                encoding: 'utf8',
                mode: 0o600,
            });
        }
        catch (error) {
            // Gracefully handle errors - don't crash the application
            console.error('FileOutput: Failed to write log entries:', error);
            // Put entries back in queue for retry (but limit retries)
            if (this.writeQueue.length < this.maxQueueSize / 2) {
                this.writeQueue.unshift(...entriesToWrite);
            }
        }
        finally {
            this.isWriting = false;
        }
    }
    async ensureDirectoryExists() {
        try {
            await fs.access(this.debugDir);
        }
        catch {
            await fs.mkdir(this.debugDir, {
                recursive: true,
                mode: 0o700,
            });
        }
    }
    async checkFileRotation() {
        try {
            const stats = await fs.stat(this.currentLogFile);
            // Rotate by size
            if (stats.size >= this.maxFileSize) {
                this.currentLogFile = this.generateLogFileName();
                return;
            }
            // Rotate by date (daily rotation)
            const fileDate = new Date(stats.birthtime);
            const today = new Date();
            if (fileDate.toDateString() !== today.toDateString()) {
                this.currentLogFile = this.generateLogFileName();
            }
        }
        catch {
            // File doesn't exist yet, that's fine
        }
    }
    generateLogFileName() {
        const now = new Date();
        const dateString = now.toISOString().split('T')[0]; // YYYY-MM-DD
        const timeString = now.toTimeString().split(' ')[0].replace(/:/g, '-'); // HH-MM-SS
        return join(this.debugDir, `llxprt-debug-${dateString}-${timeString}.jsonl`);
    }
}
//# sourceMappingURL=FileOutput.js.map