import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';

describe('logger', () => {
  let stderrSpy: ReturnType<typeof vi.spyOn>;

  beforeEach(() => {
    stderrSpy = vi.spyOn(process.stderr, 'write').mockImplementation(() => true);
    vi.resetModules();
  });

  afterEach(() => {
    stderrSpy.mockRestore();
    delete process.env.NODE_ENV;
    delete process.env.LOG_LEVEL;
  });

  it('emits JSON line to stderr in production', async () => {
    process.env.NODE_ENV  = 'production';
    process.env.LOG_LEVEL = 'info';
    const { logger } = await import('../lib/logger.js');

    logger.error('something went wrong', { code: 42 });

    expect(stderrSpy).toHaveBeenCalledOnce();
    const written = String(stderrSpy.mock.calls[0][0]);
    const parsed  = JSON.parse(written.trim());
    expect(parsed.level).toBe('error');
    expect(parsed.msg).toBe('something went wrong');
    expect(parsed.code).toBe(42);
    expect(typeof parsed.time).toBe('number');
  });

  it('suppresses messages below minLevel', async () => {
    process.env.NODE_ENV  = 'production';
    process.env.LOG_LEVEL = 'error';
    const { logger } = await import('../lib/logger.js');

    logger.info('this should be suppressed');

    expect(stderrSpy).not.toHaveBeenCalled();
  });

  it('emits warn and error when LOG_LEVEL=warn', async () => {
    process.env.NODE_ENV  = 'production';
    process.env.LOG_LEVEL = 'warn';
    const { logger } = await import('../lib/logger.js');

    logger.debug('suppressed');
    logger.info('suppressed');
    logger.warn('kept');
    logger.error('kept');

    expect(stderrSpy).toHaveBeenCalledTimes(2);
  });

  it('includes extra context fields in JSON output', async () => {
    process.env.NODE_ENV  = 'production';
    process.env.LOG_LEVEL = 'info';
    const { logger } = await import('../lib/logger.js');

    logger.info('test', { foo: 'bar', num: 99 });

    const written = String(stderrSpy.mock.calls[0][0]);
    const parsed  = JSON.parse(written.trim());
    expect(parsed.foo).toBe('bar');
    expect(parsed.num).toBe(99);
  });
});
