/**
 * Basic Logger Tests
 *
 * Tests for the core logger functionality and utilities.
 */

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

describe('Basic Logger Tests', () => {
  let logger: Logger;
  let testLoggerInstance: ReturnType<typeof loggerTestHelpers.createTestLogger>;

  beforeEach(() => {
    testLoggerInstance = loggerTestHelpers.createTestLogger('utils-test');
    logger = testLoggerInstance.logger;
  });
  afterEach(async () => {
    testLoggerInstance.clearCapturedLogs();
    // Clear any global logger cache
    await shutdownLoggers();
  });

  describe('Logger Factory Functions', () => {
    it('should create logger with getLogger', () => {
      expect(typeof getLogger).toBe('function');

      // Test that getLogger doesn't throw
      expect(() => {
        const anotherTestLoggerInstance = loggerTestHelpers.createTestLogger('factory-test');
        anotherTestLoggerInstance.logger.info('Factory test');
      }).not.toThrow();
    });
  });

  describe('Logger Methods', () => {
    it('should have all required logging methods', () => {
      expect(typeof logger.debug).toBe('function');
      expect(typeof logger.info).toBe('function');
      expect(typeof logger.warn).toBe('function');
      expect(typeof logger.error).toBe('function');
      expect(typeof logger.child).toBe('function');
    });

    it('should log with different message types', () => {
      // String message
      logger.info('String message');

      // Object message
      logger.info({ event: 'object_message', data: 'test' });

      const logs = testLoggerInstance.getCapturedLogs();
      expect(logs.length).toBe(2);
      expect(logs[0].msg).toBe('String message');
      expect(logs[1].level).toBe('info');
    });

    it('should handle metadata correctly', () => {
      const metadata = {
        userId: 'user123',
        sessionId: 'session456',
        requestId: 'req789',
      };

      logger.info('Request processed', metadata);

      const logs = testLoggerInstance.getCapturedLogs();
      expect(logs.length).toBe(1);
      expect(logs[0].userId).toBe('user123');
      expect(logs[0].sessionId).toBe('session456');
      expect(logs[0].requestId).toBe('req789');
    });
  });

  describe('Child Logger Functionality', () => {
    it('should create child loggers with additional context', () => {
      const childLogger = logger.child({
        module: 'payment',
        version: '1.0.0',
      });

      childLogger.info('Payment processed');

      const logs = testLoggerInstance.getCapturedLogs();
      expect(logs.length).toBe(1);
      expect(logs[0].msg).toBe('Payment processed');
    });

    it('should inherit service name in child loggers', () => {
      const childLogger = logger.child({ operation: 'test' });
      childLogger.info('Child operation');

      const logs = testLoggerInstance.getCapturedLogs();
      expect(logs.length).toBe(1);
      expect(logs[0].service).toBe('utils-test');
    });
  });

  describe('Error Normalization', () => {
    it('should handle Error objects', () => {
      const error = new Error('Test error');
      error.stack = 'Error stack trace';

      logger.error('Error test', error);

      const logs = testLoggerInstance.getCapturedLogs();
      expect(logs.length).toBe(1);
      expect(logs[0].level).toBe('error');
    });

    it('should handle error-like objects', () => {
      const errorLike = {
        name: 'ValidationError',
        message: 'Invalid input',
        code: 'VALIDATION_FAILED',
      };

      logger.error('Validation failed', { error: errorLike });

      const logs = testLoggerInstance.getCapturedLogs();
      expect(logs.length).toBe(1);
      expect(logs[0].level).toBe('error');
    });

    it('should handle primitive error values', () => {
      logger.error('Simple error', { error: 'Error string' });

      const logs = testLoggerInstance.getCapturedLogs();
      expect(logs.length).toBe(1);
      expect(logs[0].level).toBe('error');
    });
  });

  describe('Service Context', () => {
    it('should include service name in all logs', () => {
      logger.debug('Debug message');
      logger.info('Info message');
      logger.warn('Warn message');
      logger.error('Error message');

      const logs = testLoggerInstance.getCapturedLogs();
      expect(logs.length).toBe(4);

      logs.forEach(log => {
        expect(log.service).toBe('utils-test');
      });
    });

    it('should support different service names', () => {
      const logger1Instance = loggerTestHelpers.createTestLogger('service-one');
      const logger2Instance = loggerTestHelpers.createTestLogger('service-two');

      logger1Instance.logger.info('Message from service one');
      logger2Instance.logger.info('Message from service two');

      // Since each logger instance has its own capture, we check them separately
      // or combine them if that's the desired test logic.
      // For this test, it seems we want to ensure they are separate.
      const logs1 = logger1Instance.getCapturedLogs();
      expect(logs1.length).toBe(1);
      expect(logs1[0].service).toBe('service-one');

      const logs2 = logger2Instance.getCapturedLogs();
      expect(logs2.length).toBe(1);
      expect(logs2[0].service).toBe('service-two');
    });
  });
});
