import { beforeEach, describe, expect, it } from 'bun:test';
import { getLogger, Logger, setLoggerConfig, shutdownLoggers } from '../src/logger';

describe('Logger', () => {
  beforeEach(async () => {
    // Reset logger state
    await shutdownLoggers();
  });

  it('should create a logger instance', () => {
    const logger = getLogger('test');
    expect(logger).toBeDefined();
    expect(logger).toBeInstanceOf(Logger);
  });

  it('should use same pino instance for same name', async () => {
    await shutdownLoggers(); // Reset first
    const logger1 = getLogger('test');
    const logger2 = getLogger('test');
    // While Logger instances are different, they should share the same pino instance
    expect(logger1).not.toBe(logger2); // Different Logger instances
    // But they have the same service name
    expect((logger1 as any).serviceName).toBe((logger2 as any).serviceName);
  });

  it('should create different instances for different names', () => {
    const logger1 = getLogger('test1');
    const logger2 = getLogger('test2');
    expect(logger1).not.toBe(logger2);
  });

  it('should have logging methods', () => {
    const logger = getLogger('test');
    expect(typeof logger.info).toBe('function');
    expect(typeof logger.error).toBe('function');
    expect(typeof logger.warn).toBe('function');
    expect(typeof logger.debug).toBe('function');
    expect(typeof logger.trace).toBe('function');
  });

  it('should create child logger', () => {
    const logger = getLogger('parent');
    const child = logger.child('child');
    expect(child).toBeDefined();
    expect(child).toBeInstanceOf(Logger);
  });

  it('should accept metadata in log methods', () => {
    const logger = getLogger('test');

    // These should not throw
    logger.info('Test message');
    logger.info('Test message', { key: 'value' });
    logger.error('Error message', { error: new Error('test') });
    logger.warn('Warning', { count: 5 });
    logger.debug('Debug info', { data: [1, 2, 3] });
    logger.trace('Trace details', { nested: { value: true } });
  });

  it('should format log messages', () => {
    const logger = getLogger('test');

    // Just verify the logger can log without errors
    // The actual format is handled by pino-pretty which outputs to stdout
    expect(() => {
      logger.info('Test message');
      logger.warn('Warning message');
      logger.error('Error message');
    }).not.toThrow();
  });

  it('should set logger config', () => {
    setLoggerConfig({
      logLevel: 'debug',
    });

    const logger = getLogger('test');
    expect(logger).toBeDefined();
  });

  it('should handle shutdown', async () => {
    await shutdownLoggers(); // Reset first
    const logger1 = getLogger('test1');
    const _logger2 = getLogger('test2'); // not used, just to ensure multiple loggers can be created

    // Store references
    const logger1Ref = logger1;

    await shutdownLoggers();

    // Should create new instances after shutdown
    const logger3 = getLogger('test1');
    expect(logger3).not.toBe(logger1Ref);
  });

  it('should handle log levels', async () => {
    await shutdownLoggers(); // Reset first
    setLoggerConfig({ logLevel: 'warn' });
    const logger = getLogger('test');

    // Just verify that log methods exist and don't throw
    // The actual level filtering is handled by pino
    expect(() => {
      logger.trace('Trace'); // Should not log
      logger.debug('Debug'); // Should not log
      logger.info('Info'); // Should not log
      logger.warn('Warn'); // Should log
      logger.error('Error'); // Should log
    }).not.toThrow();

    // Clean up
    await shutdownLoggers();
  });
});
