// src/services/logger.client.test.ts
import { describe, it, expect, vi, afterEach } from 'vitest';

// IMPORTANT: Unmock the module to ensure we test the REAL implementation,
// not an auto-mocked version that doesn't actually call console methods.
vi.unmock('./logger.client');

import { logger } from './logger.client';

console.log('Logger implementation:', logger);

describe('Client Logger', () => {
  afterEach(() => {
    // Restore all spies
    vi.restoreAllMocks();
  });

  it('logger.info calls console.log with [INFO] prefix', () => {
    // Access globalThis.console to ensure we spy on the environment's actual console
    const spy = vi.spyOn(globalThis.console, 'log').mockImplementation(() => {});
    const message = 'test info';
    const data = { foo: 'bar' };

    logger.info(message, data);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith(`[INFO] ${message}`, data);
  });

  it('logger.info calls console.log correctly when the first argument is an object', () => {
    const spy = vi.spyOn(globalThis.console, 'log').mockImplementation(() => {});
    const message = 'test info with object';
    const data = { foo: 'bar' };

    logger.info(data, message, 'extra');

    expect(spy).toHaveBeenCalledTimes(1);
    // The implementation logs the message, then the object, then any extra args
    expect(spy).toHaveBeenCalledWith(`[INFO] ${message}`, data, 'extra');
  });

  it('logger.info calls console.log correctly when only an object is provided', () => {
    const spy = vi.spyOn(globalThis.console, 'log').mockImplementation(() => {});
    const data = { foo: 'bar' };

    logger.info(data);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith('[INFO] ', data);
  });

  it('logger.warn calls console.warn with [WARN] prefix', () => {
    const spy = vi.spyOn(globalThis.console, 'warn').mockImplementation(() => {});
    const message = 'test warn';

    logger.warn(message);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith(`[WARN] ${message}`);
  });

  it('logger.warn calls console.warn correctly when the first argument is an object', () => {
    const spy = vi.spyOn(globalThis.console, 'warn').mockImplementation(() => {});
    const message = 'test warn with object';
    const data = { foo: 'bar' };

    logger.warn(data, message);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith(`[WARN] ${message}`, data);
  });

  it('logger.warn calls console.warn correctly when only an object is provided', () => {
    const spy = vi.spyOn(globalThis.console, 'warn').mockImplementation(() => {});
    const data = { foo: 'bar' };

    logger.warn(data);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith('[WARN] ', data);
  });

  it('logger.error calls console.error with [ERROR] prefix', () => {
    const spy = vi.spyOn(globalThis.console, 'error').mockImplementation(() => {});
    const message = 'test error';
    const err = new Error('fail');

    logger.error(message, err);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith(`[ERROR] ${message}`, err);
  });

  it('logger.error calls console.error correctly when the first argument is an object', () => {
    const spy = vi.spyOn(globalThis.console, 'error').mockImplementation(() => {});
    const message = 'test error with object';
    const data = { errorCode: 123 };

    logger.error(data, message);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith(`[ERROR] ${message}`, data);
  });

  it('logger.error calls console.error correctly when only an object is provided', () => {
    const spy = vi.spyOn(globalThis.console, 'error').mockImplementation(() => {});
    const data = { errorCode: 123 };

    logger.error(data);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith('[ERROR] ', data);
  });

  it('logger.debug calls console.debug with [DEBUG] prefix', () => {
    const spy = vi.spyOn(globalThis.console, 'debug').mockImplementation(() => {});
    const message = 'test debug';

    logger.debug(message);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith(`[DEBUG] ${message}`);
  });

  it('logger.debug calls console.debug correctly when the first argument is an object', () => {
    const spy = vi.spyOn(globalThis.console, 'debug').mockImplementation(() => {});
    const message = 'test debug with object';
    const data = { details: 'verbose' };

    logger.debug(data, message);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith(`[DEBUG] ${message}`, data);
  });

  it('logger.debug calls console.debug correctly when only an object is provided', () => {
    const spy = vi.spyOn(globalThis.console, 'debug').mockImplementation(() => {});
    const data = { details: 'verbose' };

    logger.debug(data);

    expect(spy).toHaveBeenCalledTimes(1);
    expect(spy).toHaveBeenCalledWith('[DEBUG] ', data);
  });
});
