/**
 * Debug logging utilities for takt
 * Writes debug logs to file when enabled in config.
 * When verbose console is enabled, also outputs to stderr.
 */
import { existsSync, appendFileSync, mkdirSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
/**
 * Debug logger singleton.
 * Manages file-based debug logging and verbose console output.
 */
export class DebugLogger {
    static instance = null;
    debugEnabled = false;
    traceEnabled = false;
    debugLogFile = null;
    debugPromptsLogFile = null;
    initialized = false;
    verboseConsoleEnabled = false;
    constructor() { }
    static getInstance() {
        if (!DebugLogger.instance) {
            DebugLogger.instance = new DebugLogger();
        }
        return DebugLogger.instance;
    }
    /** Reset singleton for testing */
    static resetInstance() {
        DebugLogger.instance = null;
    }
    /** Get default debug log file prefix */
    static getDefaultLogPrefix(projectDir) {
        const timestamp = new Date().toISOString().replace(/[:.]/g, '-').slice(0, 19);
        const runSlug = `debug-${timestamp}`;
        return join(projectDir, '.takt', 'runs', runSlug, 'logs', runSlug);
    }
    /** Initialize debug logger from config */
    init(config, projectDir) {
        if (this.initialized) {
            return;
        }
        this.debugEnabled = config?.enabled ?? false;
        this.traceEnabled = config?.trace ?? false;
        if (this.debugEnabled) {
            if (config?.logFile) {
                this.debugLogFile = config.logFile;
                if (config.logFile.endsWith('.log')) {
                    this.debugPromptsLogFile = config.logFile.slice(0, -4) + '-prompts.jsonl';
                }
                else {
                    this.debugPromptsLogFile = `${config.logFile}-prompts.jsonl`;
                }
            }
            else if (projectDir) {
                const logPrefix = DebugLogger.getDefaultLogPrefix(projectDir);
                this.debugLogFile = `${logPrefix}.log`;
                this.debugPromptsLogFile = `${logPrefix}-prompts.jsonl`;
            }
            if (this.debugLogFile) {
                const logDir = dirname(this.debugLogFile);
                if (!existsSync(logDir)) {
                    mkdirSync(logDir, { recursive: true });
                }
                const header = [
                    '='.repeat(60),
                    `TAKT Debug Log`,
                    `Started: ${new Date().toISOString()}`,
                    `Project: ${projectDir || 'N/A'}`,
                    '='.repeat(60),
                    '',
                ].join('\n');
                writeFileSync(this.debugLogFile, header, 'utf-8');
            }
            if (this.debugPromptsLogFile) {
                const promptsLogDir = dirname(this.debugPromptsLogFile);
                if (!existsSync(promptsLogDir)) {
                    mkdirSync(promptsLogDir, { recursive: true });
                }
                writeFileSync(this.debugPromptsLogFile, '', 'utf-8');
            }
        }
        this.initialized = true;
    }
    /** Reset state (for testing) */
    reset() {
        this.debugEnabled = false;
        this.traceEnabled = false;
        this.debugLogFile = null;
        this.debugPromptsLogFile = null;
        this.initialized = false;
        this.verboseConsoleEnabled = false;
    }
    /** Enable or disable verbose console output */
    setVerboseConsole(enabled) {
        this.verboseConsoleEnabled = enabled;
    }
    /** Check if verbose console is enabled */
    isVerboseConsole() {
        return this.verboseConsoleEnabled;
    }
    /** Check if debug is enabled */
    isEnabled() {
        return this.debugEnabled;
    }
    /** Get current debug log file path */
    getLogFile() {
        return this.debugLogFile;
    }
    /** Get current debug prompts log file path */
    getPromptsLogFile() {
        return this.debugPromptsLogFile;
    }
    /** Format log message with timestamp and level */
    static formatLogMessage(level, component, message, data) {
        const timestamp = new Date().toISOString();
        const prefix = `[${timestamp}] [${level.toUpperCase()}] [${component}]`;
        let logLine = `${prefix} ${message}`;
        if (data !== undefined) {
            try {
                const dataStr = typeof data === 'string' ? data : JSON.stringify(data, null, 2);
                logLine += `\n${dataStr}`;
            }
            catch {
                logLine += `\n[Unable to serialize data]`;
            }
        }
        return logLine;
    }
    /** Format a compact console log line */
    static formatConsoleMessage(level, component, message) {
        const timestamp = new Date().toISOString().slice(11, 23);
        return `[${timestamp}] [${level}] [${component}] ${message}`;
    }
    /** Write a log entry to verbose console (stderr) and/or file */
    writeLog(level, component, message, data) {
        if (this.verboseConsoleEnabled) {
            process.stderr.write(DebugLogger.formatConsoleMessage(level, component, message) + '\n');
        }
        if (!this.debugEnabled || !this.debugLogFile) {
            return;
        }
        const logLine = DebugLogger.formatLogMessage(level, component, message, data);
        try {
            appendFileSync(this.debugLogFile, logLine + '\n', 'utf-8');
        }
        catch {
            // Silently fail - logging errors should not interrupt main flow
        }
    }
    /** Write a prompt/response debug log entry */
    writePromptLog(record) {
        if (!this.debugEnabled || !this.debugPromptsLogFile) {
            return;
        }
        try {
            appendFileSync(this.debugPromptsLogFile, JSON.stringify(record) + '\n', 'utf-8');
        }
        catch {
            // Silently fail - logging errors should not interrupt main flow
        }
    }
    /** Create a scoped logger for a component */
    createLogger(component) {
        return {
            trace: (message, data) => {
                if (this.traceEnabled)
                    this.writeLog('TRACE', component, message, data);
            },
            debug: (message, data) => this.writeLog('DEBUG', component, message, data),
            info: (message, data) => this.writeLog('INFO', component, message, data),
            warn: (message, data) => this.writeLog('WARN', component, message, data),
            error: (message, data) => this.writeLog('ERROR', component, message, data),
            enter: (funcName, args) => this.writeLog('DEBUG', component, `>> ${funcName}()`, args),
            exit: (funcName, result) => this.writeLog('DEBUG', component, `<< ${funcName}()`, result),
        };
    }
}
// ---- Module-level functions ----
export function initDebugLogger(config, projectDir) {
    DebugLogger.getInstance().init(config, projectDir);
}
export function resetDebugLogger() {
    DebugLogger.getInstance().reset();
}
export function setVerboseConsole(enabled) {
    DebugLogger.getInstance().setVerboseConsole(enabled);
}
export function isVerboseConsole() {
    return DebugLogger.getInstance().isVerboseConsole();
}
export function isDebugEnabled() {
    return DebugLogger.getInstance().isEnabled();
}
export function getDebugLogFile() {
    return DebugLogger.getInstance().getLogFile();
}
export function getDebugPromptsLogFile() {
    return DebugLogger.getInstance().getPromptsLogFile();
}
export function debugLog(component, message, data) {
    DebugLogger.getInstance().writeLog('DEBUG', component, message, data);
}
export function infoLog(component, message, data) {
    DebugLogger.getInstance().writeLog('INFO', component, message, data);
}
export function errorLog(component, message, data) {
    DebugLogger.getInstance().writeLog('ERROR', component, message, data);
}
export function writePromptLog(record) {
    DebugLogger.getInstance().writePromptLog(record);
}
export function traceEnter(component, funcName, args) {
    debugLog(component, `>> ${funcName}()`, args);
}
export function traceExit(component, funcName, result) {
    debugLog(component, `<< ${funcName}()`, result);
}
export function createLogger(component) {
    return DebugLogger.getInstance().createLogger(component);
}
//# sourceMappingURL=debug.js.map