import pino from "pino";
import env from "./env.js";
// Default logger instance - will be initialized with initializeLogger
let logger;
// Track if logger has been initialized
let isInitialized = false;
/**
 * Initialize the logger with custom options
 * This should be called once at server startup
 */
export function initializeLogger(options) {
    const nodeEnv = env.get("NODE_ENV") || "development";
    const isPretty = options?.pretty ?? (nodeEnv === "development");
    // Determine log level from options, env, or defaults
    const level = options?.level
        ?? env.get("LOG_LEVEL")
        ?? "info";
    // Build pino options
    const pinoOptions = {
        level,
        ...options?.options,
    };
    // If transport is specified, use it
    if (options?.transport) {
        pinoOptions.transport = options.transport;
        logger = pino(pinoOptions);
    }
    // If destination is specified, use it
    else if (options?.destination) {
        logger = pino(pinoOptions, options.destination);
    }
    // If pretty mode is enabled, use pino-pretty transport
    else if (isPretty) {
        pinoOptions.transport = {
            target: "pino-pretty",
            options: {
                colorize: true,
                translateTime: "SYS:standard",
                ignore: "pid,hostname",
            },
        };
        logger = pino(pinoOptions);
    }
    // Default: stdout (stdio)
    else {
        logger = pino(pinoOptions);
    }
    isInitialized = true;
    // Override console methods to use pino logger
    overrideConsoleMethods();
    return logger;
}
/**
 * Get the logger instance
 * If not initialized, creates a default logger
 */
export function getLogger() {
    if (!isInitialized) {
        return initializeLogger();
    }
    return logger;
}
/**
 * Serialize an Error object to a plain object with all properties
 */
function serializeError(err) {
    const serialized = {
        name: err.name,
        message: err.message,
        stack: err.stack,
    };
    // Copy any additional enumerable and non-enumerable properties
    for (const key of Object.getOwnPropertyNames(err)) {
        if (key !== 'name' && key !== 'message' && key !== 'stack') {
            serialized[key] = err[key];
        }
    }
    return serialized;
}
/**
 * Process arguments for logging, serializing any Error objects
 */
function processLogArgs(args) {
    return args.map(arg => {
        if (arg instanceof Error) {
            return serializeError(arg);
        }
        return arg;
    });
}
/**
 * Override console methods to use pino logger
 * This maintains backward compatibility with existing code using console.*
 */
function overrideConsoleMethods() {
    const logLevel = env.get("LOG_LEVEL") || "info";
    const isDebugEnabled = ["debug", "trace"].includes(logLevel);
    const warnStackEnabled = env.get("LOG_WARN_STACK") === "true";
    // Store original console methods for potential direct access
    const originalConsole = {
        log: console.log,
        info: console.info,
        warn: console.warn,
        error: console.error,
        debug: console.debug,
    };
    // Override console.log - only logs when log level is debug or trace (maps to debug level)
    console.log = function (...args) {
        if (isDebugEnabled) {
            if (args.length === 1 && typeof args[0] === "string") {
                logger.debug(args[0]);
            }
            else if (args.length === 1) {
                logger.debug(args[0]);
            }
            else {
                logger.debug({ data: processLogArgs(args) }, String(args[0]));
            }
        }
    };
    // Override console.info - always logs (maps to info level)
    console.info = function (...args) {
        if (args.length === 1 && typeof args[0] === "string") {
            logger.info(args[0]);
        }
        else if (args.length === 1) {
            logger.info(args[0]);
        }
        else {
            logger.info({ data: processLogArgs(args) }, String(args[0]));
        }
    };
    // Override console.warn - always logs (maps to warn level)
    console.warn = function (...args) {
        // Optionally capture stack trace for warnings
        const stackTrace = warnStackEnabled ? new Error().stack?.split('\n').slice(2).join('\n') : undefined;
        if (args.length === 1 && typeof args[0] === "string") {
            if (stackTrace) {
                logger.warn({ stack: stackTrace }, args[0]);
            }
            else {
                logger.warn(args[0]);
            }
        }
        else if (args.length === 1 && args[0] instanceof Error) {
            logger.warn({ err: serializeError(args[0]) }, args[0].message);
        }
        else if (args.length === 1) {
            if (stackTrace) {
                logger.warn({ ...args[0], stack: stackTrace });
            }
            else {
                logger.warn(args[0]);
            }
        }
        else {
            // Check if any argument is an Error and log it properly
            const errorArg = args.find(arg => arg instanceof Error);
            if (errorArg) {
                logger.warn({ err: serializeError(errorArg), data: processLogArgs(args) }, String(args[0]));
            }
            else if (stackTrace) {
                logger.warn({ data: processLogArgs(args), stack: stackTrace }, String(args[0]));
            }
            else {
                logger.warn({ data: processLogArgs(args) }, String(args[0]));
            }
        }
    };
    // Override console.error - always logs (maps to error level)
    console.error = function (...args) {
        if (args.length === 1 && typeof args[0] === "string") {
            logger.error(args[0]);
        }
        else if (args.length === 1 && args[0] instanceof Error) {
            logger.error({ err: serializeError(args[0]) }, args[0].message);
        }
        else if (args.length === 1) {
            logger.error(args[0]);
        }
        else {
            // Check if any argument is an Error and log it properly
            const errorArg = args.find(arg => arg instanceof Error);
            if (errorArg) {
                logger.error({ err: serializeError(errorArg), data: processLogArgs(args) }, String(args[0]));
            }
            else {
                logger.error({ data: processLogArgs(args) }, String(args[0]));
            }
        }
    };
    // Override console.debug - only logs when log level is debug or trace
    console.debug = function (...args) {
        if (isDebugEnabled) {
            if (args.length === 1 && typeof args[0] === "string") {
                logger.debug(args[0]);
            }
            else if (args.length === 1) {
                logger.debug(args[0]);
            }
            else {
                logger.debug({ data: processLogArgs(args) }, String(args[0]));
            }
        }
    };
    // Store original console methods for direct access if needed
    globalThis.__originalConsole = originalConsole;
}
/**
 * Get original console methods (before override)
 */
export function getOriginalConsole() {
    return globalThis.__originalConsole;
}
// Export the logger getter as default
export default getLogger;
//# sourceMappingURL=logger.js.map