"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.StructuredLoggerFactory = exports.StructuredLogger = exports.generateCorrelationId = void 0;
/**
 * Structured logging with JSON support and correlation IDs
 */
const crypto_1 = require("crypto");
/**
 * Generate a unique correlation ID
 */
function generateCorrelationId() {
    return (0, crypto_1.randomBytes)(16).toString('hex');
}
exports.generateCorrelationId = generateCorrelationId;
/**
 * Structured logger with JSON support
 */
class StructuredLogger {
    constructor(options = {}) {
        this.levelPriority = {
            debug: 0,
            info: 1,
            warn: 2,
            error: 3,
            fatal: 4,
        };
        this.format = options.format || 'text';
        this.level = options.level || 'info';
        this.component = options.component;
        this.defaultContext = options.defaultContext || {};
        this.output =
            options.output ||
                (entry => {
                    if (this.format === 'json') {
                        console.log(JSON.stringify(entry));
                    }
                    else {
                        this.outputText(entry);
                    }
                });
    }
    outputText(entry) {
        const prefix = `[${entry.timestamp}] [${entry.level.toUpperCase()}]`;
        const component = entry.component ? ` [${entry.component}]` : '';
        const correlationId = entry.correlationId ? ` [${entry.correlationId}]` : '';
        let message = `${prefix}${component}${correlationId} ${entry.message}`;
        if (entry.context && Object.keys(entry.context).length > 0) {
            const contextStr = Object.entries(entry.context)
                .filter(([key]) => key !== 'correlationId')
                .map(([key, value]) => `${key}=${JSON.stringify(value)}`)
                .join(' ');
            if (contextStr) {
                message += ` ${contextStr}`;
            }
        }
        if (entry.error) {
            message += ` error=${entry.error.name}: ${entry.error.message}`;
            if (entry.error.stack) {
                message += `\n${entry.error.stack}`;
            }
        }
        if (entry.duration !== undefined) {
            message += ` duration=${entry.duration}ms`;
        }
        console.log(message);
    }
    shouldLog(level) {
        return this.levelPriority[level] >= this.levelPriority[this.level];
    }
    createEntry(level, message, context, error, duration) {
        const entry = {
            timestamp: new Date().toISOString(),
            level,
            message,
            component: this.component,
        };
        // Merge contexts
        const fullContext = { ...this.defaultContext, ...context };
        if (Object.keys(fullContext).length > 0) {
            entry.context = fullContext;
            if (fullContext.correlationId) {
                entry.correlationId = fullContext.correlationId;
            }
        }
        if (error) {
            entry.error = {
                name: error.name,
                message: error.message,
                stack: error.stack,
            };
        }
        if (duration !== undefined) {
            entry.duration = duration;
        }
        return entry;
    }
    debug(message, context, duration) {
        if (this.shouldLog('debug')) {
            this.output(this.createEntry('debug', message, context, undefined, duration));
        }
    }
    info(message, context, duration) {
        if (this.shouldLog('info')) {
            this.output(this.createEntry('info', message, context, undefined, duration));
        }
    }
    warn(message, context, error, duration) {
        if (this.shouldLog('warn')) {
            this.output(this.createEntry('warn', message, context, error, duration));
        }
    }
    error(message, error, context, duration) {
        if (this.shouldLog('error')) {
            this.output(this.createEntry('error', message, context, error, duration));
        }
    }
    fatal(message, error, context) {
        if (this.shouldLog('fatal')) {
            this.output(this.createEntry('fatal', message, context, error));
        }
    }
    /**
     * Create a child logger with additional context
     */
    child(context) {
        return new StructuredLogger({
            format: this.format,
            level: this.level,
            component: this.component,
            defaultContext: { ...this.defaultContext, ...context },
            output: this.output,
        });
    }
    /**
     * Create a timer for measuring operation duration
     */
    startTimer() {
        const start = Date.now();
        return () => Date.now() - start;
    }
}
exports.StructuredLogger = StructuredLogger;
/**
 * Global logger factory with structured logging support
 */
class StructuredLoggerFactory {
    /**
     * Configure global logging options
     */
    static configure(options) {
        this.globalOptions = { ...this.globalOptions, ...options };
        // Update existing loggers
        for (const [component] of this.loggers) {
            this.loggers.set(component, new StructuredLogger({
                ...this.globalOptions,
                component,
            }));
        }
    }
    /**
     * Get or create a logger for a component
     */
    static getLogger(component) {
        const key = component || 'default';
        if (!this.loggers.has(key)) {
            this.loggers.set(key, new StructuredLogger({
                ...this.globalOptions,
                component,
            }));
        }
        return this.loggers.get(key);
    }
    /**
     * Create a logger with correlation ID
     */
    static getLoggerWithCorrelation(component, correlationId) {
        const id = correlationId || generateCorrelationId();
        return this.getLogger(component).child({ correlationId: id });
    }
}
exports.StructuredLoggerFactory = StructuredLoggerFactory;
StructuredLoggerFactory.loggers = new Map();
StructuredLoggerFactory.globalOptions = {
    format: process.env.LOG_FORMAT === 'json' ? 'json' : 'text',
    level: process.env.LOG_LEVEL || 'info',
};
//# sourceMappingURL=structured-logger.js.map