// #region CotLoggerTest [C:3] [TYPE Module] [SEMANTICS test, cot-logger, molecular, logging]
// @BRIEF Unit tests for the Molecular CoT logger — JSON structure, marker levels, trace ID propagation,
//   and console output verification.
// @LAYER Tests
// @RELATION BINDS_TO -> [CotLogger]
// @TEST_CONTRACT: log -> Produces valid JSON line with correct marker and level
// @TEST_CONTRACT: log -> EXPLORE marker emits WARNING level and requires error field
// @TEST_CONTRACT: setTraceId -> Updates trace ID for subsequent log calls
// @TEST_CONTRACT: getTraceId -> Returns "no-trace" if none set
// @TEST_CONTRACT: initTraceId -> Alias for getTraceId

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

describe('CoT Logger — setTraceId / getTraceId / initTraceId', () => {
	beforeEach(() => {
		// Reset module state between tests by clearing module registry
		vi.resetModules();
	});

	it('getTraceId returns "no-trace" when no ID is set', async () => {
		const { getTraceId } = await import('$lib/cot-logger.js');
		expect(getTraceId()).toBe('no-trace');
	});

	it('setTraceId updates the trace ID', async () => {
		const { setTraceId, getTraceId } = await import('$lib/cot-logger.js');
		setTraceId('trace-abc-123');
		expect(getTraceId()).toBe('trace-abc-123');
	});

	it('initTraceId returns the same value as getTraceId', async () => {
		const { initTraceId, getTraceId, setTraceId } = await import('$lib/cot-logger.js');
		setTraceId('trace-xyz');
		expect(initTraceId()).toBe('trace-xyz');
		expect(initTraceId()).toBe(getTraceId());
	});

	it('setTraceId can override an existing trace ID', async () => {
		const { setTraceId, getTraceId } = await import('$lib/cot-logger.js');
		setTraceId('first-trace');
		setTraceId('second-trace');
		expect(getTraceId()).toBe('second-trace');
	});
});

describe('CoT Logger — log() output structure', () => {
	beforeEach(() => {
		vi.resetModules();
		vi.spyOn(console, 'info').mockImplementation(() => {});
		vi.spyOn(console, 'warn').mockImplementation(() => {});
	});

	afterEach(() => {
		vi.restoreAllMocks();
	});

	it('log with REASON marker emits JSON via console.info', async () => {
		const { log, setTraceId } = await import('$lib/cot-logger.js');
		setTraceId('trace-reason');
		log('TestComponent', 'REASON', 'Starting operation', { taskId: 't1' });

		expect(console.info).toHaveBeenCalledTimes(1);
		const callArg = vi.mocked(console.info).mock.calls[0][0];
		const parsed = JSON.parse(callArg);
		expect(parsed.marker).toBe('REASON');
		expect(parsed.level).toBe('INFO');
		expect(parsed.trace_id).toBe('trace-reason');
		expect(parsed.src).toBe('TestComponent');
		expect(parsed.intent).toBe('Starting operation');
		expect(parsed.payload).toEqual({ taskId: 't1' });
		expect(parsed.error).toBeUndefined();
		expect(parsed.ts).toBeDefined();
	});

	it('log with REFLECT marker emits JSON via console.info', async () => {
		const { log, setTraceId } = await import('$lib/cot-logger.js');
		setTraceId('trace-reflect');
		log('MigrationModel', 'REFLECT', 'Operation completed', { status: 'ok' });

		expect(console.info).toHaveBeenCalledTimes(1);
		const parsed = JSON.parse(vi.mocked(console.info).mock.calls[0][0]);
		expect(parsed.marker).toBe('REFLECT');
		expect(parsed.level).toBe('INFO');
	});

	it('log with EXPLORE marker emits JSON via console.warn with WARNING level', async () => {
		const { log, setTraceId } = await import('$lib/cot-logger.js');
		setTraceId('trace-explore');
		log('ApiClient', 'EXPLORE', 'Request failed', { endpoint: '/fail' }, 'Network timeout');

		expect(console.warn).toHaveBeenCalledTimes(1);
		const parsed = JSON.parse(vi.mocked(console.warn).mock.calls[0][0]);
		expect(parsed.marker).toBe('EXPLORE');
		expect(parsed.level).toBe('WARNING');
		expect(parsed.error).toBe('Network timeout');
		expect(parsed.payload).toEqual({ endpoint: '/fail' });
	});

	it('log with EXPLORE and no error still sets WARNING level', async () => {
		const { log } = await import('$lib/cot-logger.js');
		log('Test', 'EXPLORE', 'Something odd');

		const parsed = JSON.parse(vi.mocked(console.warn).mock.calls[0][0]);
		expect(parsed.level).toBe('WARNING');
		expect(parsed.error).toBeUndefined();
	});

	it('log without payload omits payload field from JSON', async () => {
		const { log, setTraceId } = await import('$lib/cot-logger.js');
		setTraceId('t1');
		log('Comp', 'REASON', 'Simple log');

		const parsed = JSON.parse(vi.mocked(console.info).mock.calls[0][0]);
		expect(parsed.payload).toBeUndefined();
		expect(parsed.intent).toBe('Simple log');
	});

	it('log with only error and no payload includes error field', async () => {
		const { log, setTraceId } = await import('$lib/cot-logger.js');
		setTraceId('t-err');
		log('Test', 'EXPLORE', 'Error occurred', undefined, 'Something broke');

		const parsed = JSON.parse(vi.mocked(console.warn).mock.calls[0][0]);
		expect(parsed.error).toBe('Something broke');
		expect(parsed.payload).toBeUndefined();
	});

	it('ts field is a valid ISO string', async () => {
		const { log, setTraceId } = await import('$lib/cot-logger.js');
		setTraceId('t-ts');
		log('Test', 'REASON', 'Timestamp check');

		const parsed = JSON.parse(vi.mocked(console.info).mock.calls[0][0]);
		expect(new Date(parsed.ts).toISOString()).toBe(parsed.ts);
	});
});
// #endregion CotLoggerTest
