// #region UseReviewSessionTest.EdgeCases [C:2] [TYPE Module] [SEMANTICS test, dataset-review, session, edge, coverage]
// @BRIEF Supplementary edge case tests for dataset review session composable — applySessionVersionInline, handlePreviewUpdated readiness_state, buildAssistantContextPromptInline with empty context, primaryActionHandler fallback.
// @RELATION DEPENDS_ON -> [UseReviewSession]
// @TEST_EDGE: null_version -> applySessionVersionInline returns session unchanged when version is null/undefined
// @TEST_EDGE: empty_prompt -> buildAssistantContextPromptInline returns prompt without context when prompt is empty
// @TEST_EDGE: run_ready_transition -> handlePreviewUpdated with run_ready readiness_state preserves it

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

vi.mock('$lib/api', () => ({
	api: {
		fetchApi: vi.fn(),
		postApi: vi.fn(),
		deleteApi: vi.fn(),
		requestApi: vi.fn(),
		fetchApiBlob: vi.fn(),
	},
}));

vi.mock('$lib/api/datasetReview', () => ({
	requestDatasetReviewApi: vi.fn(),
	normalizeDatasetReviewDetail: vi.fn((d) => d),
	isDatasetReviewConflictError: vi.fn(),
	getDatasetReviewConflictMessage: vi.fn(),
	extractDatasetReviewVersion: vi.fn(),
}));

vi.mock('$lib/stores/datasetReviewSession.svelte.js', () => ({
	datasetReviewSessionStore: { subscribe: vi.fn() },
	setLoading: vi.fn(),
	setError: vi.fn(),
	setSession: vi.fn(),
	resetSession: vi.fn(),
}));

vi.mock('$lib/stores/assistantChat.svelte.js', () => ({
	assistantChatStore: { subscribe: vi.fn() },
	setAssistantDatasetReviewSessionId: vi.fn(),
	setAssistantSeedMessage: vi.fn(),
	setAssistantFocusTarget: vi.fn(),
}));

vi.mock('$lib/cot-logger', () => ({ log: vi.fn() }));

describe('useReviewSession — Edge Cases', () => {
	beforeEach(() => {
		vi.clearAllMocks();
	});

	// ── applySessionVersionInline edge cases ──────────────────────

	it('handleSemanticUpdated with null extractDatasetReviewVersion keeps session version', async () => {
		const { extractDatasetReviewVersion } = await import('$lib/api/datasetReview');
		vi.mocked(extractDatasetReviewVersion).mockReturnValue(null);

		const { useReviewSession } = await import('../useReviewSession.ts');
		const session = { session_id: 's1', version: 1 };
		const result = useReviewSession().handleSemanticUpdated(
			session as Record<string, unknown>,
			{ fields: [{ id: 'f1' }] } as Record<string, unknown>,
		);

		// When extractDatasetReviewVersion returns null, applySessionVersionInline
		// returns the session unchanged (nextVersion is null)
		expect(result.session?.version).toBe(1);
		expect(result.session?.semantic_fields).toEqual([{ id: 'f1' }]);
	});

	it('handleSemanticUpdated with undefined extractDatasetReviewVersion keeps session version', async () => {
		const { extractDatasetReviewVersion } = await import('$lib/api/datasetReview');
		vi.mocked(extractDatasetReviewVersion).mockReturnValue(undefined);

		const { useReviewSession } = await import('../useReviewSession.ts');
		const session = { session_id: 's1', version: 2 };
		const result = useReviewSession().handleSemanticUpdated(
			session as Record<string, unknown>,
			{ fields: [{ id: 'f2' }] } as Record<string, unknown>,
		);

		// undefined version → applySessionVersionInline returns unchanged
		expect(result.session?.version).toBe(2);
	});

	it('handleMappingUpdated with null extractDatasetReviewVersion keeps session version', async () => {
		const { extractDatasetReviewVersion } = await import('$lib/api/datasetReview');
		vi.mocked(extractDatasetReviewVersion).mockReturnValue(null);

		const { useReviewSession } = await import('../useReviewSession.ts');
		const session = { session_id: 's1', version: 3 };
		const result = useReviewSession().handleMappingUpdated(
			session as Record<string, unknown>,
			{ mappings: [{ mapping_id: 'm1' }] } as Record<string, unknown>,
		);

		expect(result.session?.version).toBe(3);
	});

	// ── buildAssistantContextPromptInline with empty context ──────

	it('handleAskAiContext with empty prompt generates default help prompt without context', async () => {
		const scrollIntoView = vi.fn();
		document.getElementById = vi.fn().mockReturnValue({ scrollIntoView });
		const focusFn = vi.fn();
		const seedFn = vi.fn();

		const { useReviewSession } = await import('../useReviewSession.ts');
		useReviewSession().handleAskAiContext(
			{ target: 'mapping:m1', label: 'mapping', prompt: '' } as Record<string, unknown>,
			focusFn,
			seedFn,
		);

		// prompt is empty → context is "" → no "Context:" segment
		expect(seedFn).toHaveBeenCalledWith('Help review mapping. Section: workspace.');
	});

	it('handleAskAiContext with improve mode and empty prompt', async () => {
		const scrollIntoView = vi.fn();
		document.getElementById = vi.fn().mockReturnValue({ scrollIntoView });
		const focusFn = vi.fn();
		const seedFn = vi.fn();

		const { useReviewSession } = await import('../useReviewSession.ts');
		useReviewSession().handleAskAiContext(
			{ target: 'mapping:m1', mode: 'improve', label: 'mapping', prompt: '' } as Record<string, unknown>,
			focusFn,
			seedFn,
		);

		expect(seedFn).toHaveBeenCalledWith('Improve mapping. Section: workspace.');
	});

	it('handleAskAiContext with undefined prompt defaults to empty', async () => {
		const scrollIntoView = vi.fn();
		document.getElementById = vi.fn().mockReturnValue({ scrollIntoView });
		const focusFn = vi.fn();
		const seedFn = vi.fn();

		const { useReviewSession } = await import('../useReviewSession.ts');
		useReviewSession().handleAskAiContext(
			{ target: 'summary', label: 'summary' } as Record<string, unknown>,
			focusFn,
			seedFn,
		);

		expect(seedFn).toHaveBeenCalledWith('Help review summary. Section: workspace.');
	});

	// ── handlePreviewUpdated readiness_state transitions ─────────

	it('handlePreviewUpdated with run_ready readiness preserves it when preview is ready', async () => {
		const { extractDatasetReviewVersion } = await import('$lib/api/datasetReview');
		vi.mocked(extractDatasetReviewVersion).mockReturnValue(1);

		const { useReviewSession } = await import('../useReviewSession.ts');
		const session = {
			session_id: 's1',
			version: 1,
			previews: [],
			readiness_state: 'run_ready',
		};
		const result = useReviewSession().handlePreviewUpdated(
			session as Record<string, unknown>,
			{
				preview: { preview_id: 'p1', preview_status: 'ready' },
				preview_state: 'compiled',
			} as Record<string, unknown>,
		);

		// When preview_status is "ready" AND readiness_state is "run_ready",
		// the result should preserve "run_ready"
		expect(result.session?.readiness_state).toBe('run_ready');
	});

	it('handlePreviewUpdated with non-run_ready readiness changes to compiled_preview_ready', async () => {
		const { extractDatasetReviewVersion } = await import('$lib/api/datasetReview');
		vi.mocked(extractDatasetReviewVersion).mockReturnValue(1);

		const { useReviewSession } = await import('../useReviewSession.ts');
		const session = {
			session_id: 's1',
			version: 1,
			previews: [],
			readiness_state: 'draft',
		};
		const result = useReviewSession().handlePreviewUpdated(
			session as Record<string, unknown>,
			{
				preview: { preview_id: 'p1', preview_status: 'ready' },
				preview_state: 'compiled',
			} as Record<string, unknown>,
		);

		expect(result.session?.readiness_state).toBe('compiled_preview_ready');
	});

	it('handlePreviewUpdated with preview_status not ready preserves readiness_state', async () => {
		const { extractDatasetReviewVersion } = await import('$lib/api/datasetReview');
		vi.mocked(extractDatasetReviewVersion).mockReturnValue(1);

		const { useReviewSession } = await import('../useReviewSession.ts');
		const session = {
			session_id: 's1',
			version: 1,
			previews: [],
			readiness_state: 'draft',
		};
		const result = useReviewSession().handlePreviewUpdated(
			session as Record<string, unknown>,
			{
				preview: { preview_id: 'p1', preview_status: 'compiling' },
				preview_state: 'compiling',
			} as Record<string, unknown>,
		);

		// When preview_status is NOT "ready", readiness_state is unchanged
		expect(result.session?.readiness_state).toBe('draft');
	});

	// ── primaryActionHandler with default path and no question_id ─

	it('primaryActionHandler default action uses clarification target without question_id', async () => {
		const scrollIntoView = vi.fn();
		document.getElementById = vi.fn().mockReturnValue({ scrollIntoView });
		const resumeFn = vi.fn();
		const askFn = vi.fn();

		const { useReviewSession } = await import('../useReviewSession.ts');
		useReviewSession().primaryActionHandler(
			{ session_id: 's1', recommended_action: 'other' } as Record<string, unknown>,
			null, // clarificationCurrentQuestion is null — no question_id
			'seed prompt',
			resumeFn,
			askFn,
		);

		// When clarificationCurrentQuestion has no question_id and no recommended_action matches,
		// askFn is called with target "clarification" (no question_id suffix)
		expect(askFn).toHaveBeenCalledWith(
			expect.objectContaining({ target: 'clarification' }),
		);
	});

	// ── loadClarificationStateInline with session_id but no clarification_sessions ─

	it('loadSessionDetail with session_id but empty clarification_sessions returns null', async () => {
		const { api } = await import('$lib/api');
		vi.mocked(api.fetchApi).mockResolvedValue({
			session_id: 's1',
			clarification_sessions: [],
		});

		const { useReviewSession } = await import('../useReviewSession.ts');
		const result = await useReviewSession().loadSessionDetail('s1');

		expect(result.clarificationState).toBeNull();
		expect(api.fetchApi).toHaveBeenCalledTimes(1);
	});

	// ── handleMappingUpdated with result.mapping_id only (no result.mapping) ─

	it('handleMappingUpdated with result.mapping_id and no result.mapping uses result as item', async () => {
		const { extractDatasetReviewVersion } = await import('$lib/api/datasetReview');
		vi.mocked(extractDatasetReviewVersion).mockReturnValue(2);

		const { useReviewSession } = await import('../useReviewSession.ts');
		const session = { session_id: 's1', execution_mappings: [] };
		const result = useReviewSession().handleMappingUpdated(
			session as Record<string, unknown>,
			{
				mapping_id: 'm1',
				target: 'new-target',
			} as Record<string, unknown>,
		);

		// result.mapping is undefined, so mapping = result
		expect(result.session?.execution_mappings).toHaveLength(1);
		const mapping = (result.session!.execution_mappings as Record<string, unknown>[])[0];
		expect(mapping.target).toBe('new-target');
	});

	// ── handleSemanticUpdated with field_id merge (update existing field) ─

	it('handleSemanticUpdated with field_id merges into existing field', async () => {
		const { extractDatasetReviewVersion } = await import('$lib/api/datasetReview');
		vi.mocked(extractDatasetReviewVersion).mockReturnValue(3);

		const { useReviewSession } = await import('../useReviewSession.ts');
		const session = {
			session_id: 's1',
			semantic_fields: [{ field_id: 'f1', name: 'old', extra: 'keep' }],
		};
		const result = useReviewSession().handleSemanticUpdated(
			session as Record<string, unknown>,
			{
				field_id: 'f1',
				name: 'updated',
			} as Record<string, unknown>,
		);

		expect(result.session?.semantic_fields).toHaveLength(1);
		const field = (result.session!.semantic_fields as Record<string, unknown>[])[0];
		expect(field.name).toBe('updated');
		expect(field.extra).toBe('keep');
	});
});
// #endregion UseReviewSessionTest.EdgeCases
