import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import { info, error, warn, debug, setContext, clearContext, runWithContext } from '../../server/utils/logger.js'

describe('logger', () => {
  const testState = {
    originalLog: null,
    originalError: null,
    originalWarn: null,
    originalDebug: null,
    logCalls: [],
    errorCalls: [],
    warnCalls: [],
    debugCalls: [],
  }

  beforeEach(() => {
    testState.logCalls = []
    testState.errorCalls = []
    testState.warnCalls = []
    testState.debugCalls = []
    testState.originalLog = console.log
    testState.originalError = console.error
    testState.originalWarn = console.warn
    testState.originalDebug = console.debug
    console.log = vi.fn((...args) => testState.logCalls.push(args))
    console.error = vi.fn((...args) => testState.errorCalls.push(args))
    console.warn = vi.fn((...args) => testState.warnCalls.push(args))
    console.debug = vi.fn((...args) => testState.debugCalls.push(args))
  })

  afterEach(() => {
    console.log = testState.originalLog
    console.error = testState.originalError
    console.warn = testState.originalWarn
    console.debug = testState.originalDebug
  })

  it('logs info message', () => {
    info('Test message')
    expect(testState.logCalls.length).toBe(1)
    const logMsg = testState.logCalls[0][0]
    expect(logMsg).toContain('[INFO]')
    expect(logMsg).toContain('Test message')
  })

  it('includes request context when set', async () => {
    await runWithContext('req-123', 'user-456', async () => {
      info('Test message')
      const logMsg = testState.logCalls[0][0]
      expect(logMsg).toContain('req-123')
      expect(logMsg).toContain('user-456')
    })
  })

  it('includes additional context', () => {
    info('Test message', { key: 'value', count: 42 })
    const logMsg = testState.logCalls[0][0]
    expect(logMsg).toContain('key')
    expect(logMsg).toContain('value')
    expect(logMsg).toContain('42')
  })

  it('logs error with stack trace', () => {
    const err = new Error('Test error')
    error('Failed', { error: err })
    expect(testState.errorCalls.length).toBe(1)
    const errorMsg = testState.errorCalls[0][0]
    expect(errorMsg).toContain('[ERROR]')
    expect(errorMsg).toContain('Failed')
    expect(errorMsg).toContain('stack')
  })

  it('logs warning', () => {
    warn('Warning message')
    expect(testState.warnCalls.length).toBe(1)
    const warnMsg = testState.warnCalls[0][0]
    expect(warnMsg).toContain('[WARN]')
  })

  it('logs debug only in development', () => {
    const originalEnv = process.env.NODE_ENV
    process.env.NODE_ENV = 'development'
    debug('Debug message')
    expect(testState.debugCalls.length).toBe(1)
    process.env.NODE_ENV = originalEnv
  })

  it('does not log debug in production', () => {
    const originalEnv = process.env.NODE_ENV
    process.env.NODE_ENV = 'production'
    debug('Debug message')
    expect(testState.debugCalls.length).toBe(0)
    process.env.NODE_ENV = originalEnv
  })

  it('clears context', async () => {
    await runWithContext('req-123', 'user-456', async () => {
      info('Test with context')
      const logMsg = testState.logCalls[0][0]
      expect(logMsg).toContain('req-123')
    })
    // Context should be cleared after runWithContext completes
    info('Test without context')
    const logMsg = testState.logCalls[testState.logCalls.length - 1][0]
    expect(logMsg).not.toContain('req-123')
  })

  it('supports deprecated setContext/clearContext API', async () => {
    await runWithContext(null, null, async () => {
      setContext('req-123', 'user-456')
      info('Test message')
      const logMsg = testState.logCalls[0][0]
      expect(logMsg).toContain('req-123')
      expect(logMsg).toContain('user-456')
      clearContext()
      info('Test after clear')
      const logMsg2 = testState.logCalls[1][0]
      expect(logMsg2).not.toContain('req-123')
    })
  })
})
