/**
 * Logger Provider - Implements dependency injection pattern for logging
 * This file provides centralized logger management without circular dependencies
 */
import { createLogMethods } from './log-method-factory.js';
export class LoggerProvider {
    static instance = null;
    _logger = null;
    _config = null;
    _fallbackInitialized = false;
    _realDependenciesLoaded = false;
    // Lazy-loaded dependencies
    _createPinoLogger = null;
    _createConfig = null;
    constructor() {
        // Private constructor for singleton pattern
    }
    /**
     * Detect if running under Bun runtime
     * Bun's worker threads are incompatible with Pino's transport API
     */
    static isBunRuntime() {
        return typeof globalThis.Bun !== 'undefined';
    }
    /**
     * Get the singleton logger provider instance
     */
    static getInstance() {
        if (!LoggerProvider.instance) {
            LoggerProvider.instance = new LoggerProvider();
        }
        return LoggerProvider.instance;
    }
    /**
     * Initialize lazy-loaded dependencies to avoid circular imports
     */
    ensureDependenciesLoaded() {
        if (this._fallbackInitialized) {
            return;
        }
        // For now, use fallback logger synchronously to avoid circular dependencies
        // The real Pino logger will be loaded asynchronously when needed
        this._createPinoLogger = () => this.createFallbackLogger();
        this._createConfig = (config) => ({
            level: 'silent', // Default to silent for production CLI usage
            pretty: false,
            redact: [],
            correlation: false,
            serialize: false,
            ...config,
        });
        this._fallbackInitialized = true;
        // Skip loading real Pino dependencies if running under Bun
        // Bun's worker threads are incompatible with Pino's transport API (pino/file)
        // which uses thread-stream and real-require packages
        if (LoggerProvider.isBunRuntime()) {
            if (process.env.NODE_ENV === 'development') {
                // Use console directly since this._config is not yet set,
                // so createFallbackLogger() would default to 'silent' level
                console.info('[LOGGER_PROVIDER] Bun runtime detected - using fallback logger (Pino transport incompatible)');
            }
            return;
        }
        // Asynchronously load the real dependencies and replace the fallback
        this.loadRealDependencies().catch(error => {
            try {
                const fallbackLogger = this.createFallbackLogger();
                fallbackLogger.error('[LOGGER_PROVIDER] Failed to load real dependencies', {
                    error: this.formatErrorForLogging(error),
                    fallback: true,
                    source: 'logger-provider',
                    timestamp: new Date().toISOString(),
                });
            }
            catch (fallbackError) {
                // Absolute fallback to console if everything else fails
                console.error('[LOGGER_PROVIDER] Critical failure - fallback logger failed:', fallbackError, 'Original error:', error);
            }
        });
    }
    /**
     * Asynchronously load real Pino dependencies
     * Uses dynamic imports to avoid circular dependency issues
     */
    async loadRealDependencies() {
        // Skip if already loaded to prevent duplicate loading
        if (this._realDependenciesLoaded) {
            // Only log in development mode to avoid noise for end users
            if (process.env.NODE_ENV === 'development') {
                this.createFallbackLogger().debug('Real dependencies already loaded', {
                    source: 'logger-provider',
                    status: 'already-loaded',
                });
            }
            return;
        }
        const startTime = Date.now();
        // Only log in development mode to avoid noise for end users
        if (process.env.NODE_ENV === 'development') {
            this.createFallbackLogger().info('Loading real Pino dependencies', {
                source: 'logger-provider',
                method: 'dynamic-import',
                status: 'starting',
            });
        }
        try {
            // Load dependencies dynamically to avoid circular imports
            // Using Promise.all for parallel loading to improve performance
            const [pinoLogger, configModule] = await Promise.all([
                import('./pino-logger.js'),
                import('./config.js'),
            ]);
            // Verify imports were successful
            if (!pinoLogger?.createPinoLogger || !configModule?.createConfig) {
                throw new Error('Dynamic imports returned invalid modules');
            }
            this._createPinoLogger = pinoLogger.createPinoLogger;
            this._createConfig = configModule.createConfig;
            this._realDependenciesLoaded = true;
            // Don't reinitialize existing logger to avoid breaking ongoing operations
            // The real Pino logger will be used for new logger instances created after this point
            // Only log in development mode
            if (process.env.NODE_ENV === 'development') {
                this.createFallbackLogger().info('Real dependencies loaded successfully', {
                    source: 'logger-provider',
                    status: 'success',
                    duration: Date.now() - startTime,
                    modules: ['pino-logger', 'config'],
                });
            }
        }
        catch (error) {
            try {
                const fallbackLogger = this.createFallbackLogger();
                fallbackLogger.error('[LOGGER_PROVIDER] Failed to load real dependencies', {
                    error: this.formatErrorForLogging(error),
                    fallback: true,
                    source: 'logger-provider',
                    status: 'load-failed',
                    duration: Date.now() - startTime,
                });
            }
            catch (fallbackError) {
                // Absolute fallback to console if everything else fails
                console.error('[LOGGER_PROVIDER] Critical failure - fallback logger failed:', fallbackError, 'Original error:', error);
            }
            // Keep the fallback logger
        }
    }
    /**
     * Create fallback logger when dependencies fail to load
     */
    createFallbackLogger() {
        // Check current config level - default to silent for production
        const configLevel = this._config?.level || 'silent';
        const isSilent = configLevel === 'silent';
        // If silent, return a no-op logger
        if (isSilent) {
            const noOp = () => { };
            return {
                fatal: noOp,
                error: noOp,
                warn: noOp,
                info: noOp,
                http: noOp,
                debug: noOp,
                trace: noOp,
                child: (_bindings) => this.createFallbackLogger(),
                isLevelEnabled: (_level) => false,
                flush: async () => Promise.resolve(),
                flushSync: () => { },
                end: async () => Promise.resolve(),
            };
        }
        const fallbackConsole = console; // Use console as the logger
        // Create all log methods using the factory
        const logMethods = createLogMethods(fallbackConsole, {
            consolePrefix: '',
            transformArgs: (args, _level, _msg) => {
                // Note: Level prefix is handled by consolePrefix option in createLogMethod
                return args;
            },
        });
        return {
            ...logMethods,
            child: (_bindings) => this.createFallbackLogger(),
            isLevelEnabled: (_level) => true,
            flush: async () => Promise.resolve(),
            flushSync: () => { },
            end: async () => Promise.resolve(),
        };
    }
    /**
     * Create default configuration based on environment
     */
    createDefaultConfig(override = {}) {
        const isDev = process.env.NODE_ENV === 'development';
        const isTest = process.env.NODE_ENV === 'test';
        const defaultConfig = {
            level: isTest
                ? 'silent'
                : isDev
                    ? 'debug'
                    : process.env.NANOCODER_LOG_LEVEL || 'silent', // Default to silent for production/CLI usage
            pretty: isDev,
            redact: ['apiKey', 'token', 'password', 'secret'],
            correlation: true,
            serialize: !isDev,
        };
        return { ...defaultConfig, ...override };
    }
    /**
     * Initialize the logger with configuration
     */
    initializeLogger(config) {
        if (this._logger) {
            return this._logger;
        }
        this.ensureDependenciesLoaded();
        this._config = this.createDefaultConfig(config);
        this._logger =
            this._createPinoLogger?.(this._config) ?? this.createFallbackLogger();
        return this._logger;
    }
    /**
     * Get the current logger instance
     */
    getLogger() {
        if (!this._logger) {
            // Auto-initialize with defaults if not already done
            return this.initializeLogger();
        }
        return this._logger;
    }
    /**
     * Get the current configuration
     */
    getLoggerConfig() {
        return this._config;
    }
    /**
     * Create a child logger with additional context
     */
    createChildLogger(bindings) {
        const parent = this.getLogger();
        return parent.child(bindings);
    }
    /**
     * Format error for structured logging
     */
    formatErrorForLogging(error) {
        if (error instanceof Error) {
            return {
                message: error.message,
                stack: error.stack,
                name: error.name,
                cause: error.cause,
            };
        }
        return { value: error };
    }
    /**
     * Check if a log level is enabled
     */
    isLevelEnabled(level) {
        const logger = this.getLogger();
        return logger.isLevelEnabled(level);
    }
    /**
     * Reset the logger instance (useful for testing)
     */
    reset() {
        this._logger = null;
        this._config = null;
        this._fallbackInitialized = false;
        this._realDependenciesLoaded = false;
        this._createPinoLogger = null;
        this._createConfig = null;
    }
    /**
     * Flush any pending logs
     */
    async flush() {
        if (this._logger) {
            try {
                await this._logger.flush();
            }
            catch (_error) {
                // Ignore flush errors as they're usually due to logger being closed
                // This can happen in test environments or during shutdown
            }
        }
    }
    /**
     * Flush logs synchronously (for signal handlers)
     */
    flushSync() {
        if (this._logger) {
            this._logger.flushSync();
        }
    }
    /**
     * End the logger and close all streams
     */
    async end() {
        if (this._logger) {
            await this._logger.end();
            this._logger = null;
            this._config = null;
            // Don't reset dependency flags - they can be reused for new loggers
        }
    }
}
// Export the singleton instance for easy access
export const loggerProvider = LoggerProvider.getInstance();
//# sourceMappingURL=logger-provider.js.map