import { ConfigService } from '@nestjs/config';
import { AppLoggerService } from './app-logger.service';

describe('AppLoggerService', () => {
  let level = 'verbose';
  const config = { get: jest.fn(() => level) } as unknown as ConfigService;
  let stdout: jest.SpyInstance;
  let stderr: jest.SpyInstance;

  beforeEach(() => {
    level = 'verbose';
    stdout = jest.spyOn(process.stdout, 'write').mockImplementation(() => true);
    stderr = jest.spyOn(process.stderr, 'write').mockImplementation(() => true);
  });

  afterEach(() => {
    stdout.mockRestore();
    stderr.mockRestore();
  });

  it('writes structured messages, errors, traces, and HTTP metadata', () => {
    const logger = new AppLoggerService(config);
    logger.log('hello', 'Test');
    logger.warn({ id: 1 });
    logger.debug(new Error('debug failed'));
    logger.verbose('details');
    logger.logHttp({ method: 'GET', path: '/health' });
    logger.error('broken', 'trace-text', 'Test');

    expect(stdout).toHaveBeenCalledTimes(5);
    const logEntry = JSON.parse(String(stdout.mock.calls[0][0]));
    expect(logEntry).toEqual(expect.objectContaining({ level: 'log', context: 'Test', message: 'hello' }));
    const structured = JSON.parse(String(stdout.mock.calls[1][0]));
    expect(structured).toEqual(expect.objectContaining({ message: 'structured_log', payload: { id: 1 } }));
    const errorObject = JSON.parse(String(stdout.mock.calls[2][0]));
    expect(errorObject).toEqual(expect.objectContaining({ errorName: 'Error', message: 'debug failed' }));
    const http = JSON.parse(String(stdout.mock.calls[4][0]));
    expect(http).toEqual(expect.objectContaining({ context: 'HttpLogger', method: 'GET', path: '/health' }));
    const error = JSON.parse(String(stderr.mock.calls[0][0]));
    expect(error).toEqual(expect.objectContaining({ level: 'error', trace: 'trace-text' }));
  });

  it('filters messages below the configured level and defaults to log', () => {
    level = 'warn';
    const logger = new AppLoggerService(config);
    logger.log('hidden');
    logger.debug('hidden');
    logger.warn('visible');
    expect(stdout).toHaveBeenCalledTimes(1);

    (config.get as jest.Mock).mockReturnValueOnce(undefined);
    logger.verbose('default-hidden');
    expect(stdout).toHaveBeenCalledTimes(1);
  });
});
