/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

import assert from 'assert';
import { Event } from '../../../../../base/common/event.js';
import { MarkdownString } from '../../../../../base/common/htmlContent.js';
import { DisposableStore } from '../../../../../base/common/lifecycle.js';
import { ThemeIcon } from '../../../../../base/common/themables.js';
import { URI } from '../../../../../base/common/uri.js';
import { ensureNoDisposablesAreLeakedInTestSuite } from '../../../../../base/test/common/utils.js';
import { IChatSessionItem, IChatSessionItemProvider, ChatSessionStatus } from '../../common/chatSessionsService.js';
import { ChatSessionUri } from '../../common/chatUri.js';
import { AgentSessionsViewModel, IAgentSessionViewModel, LOCAL_AGENT_SESSION_TYPE, isLocalAgentSessionItem, isAgentSession, isAgentSessionsViewModel } from '../../browser/agentSessions/agentSessionViewModel.js';
import { MockChatService } from '../common/mockChatService.js';
import { MockChatSessionsService } from '../common/mockChatSessionsService.js';

suite('AgentSessionsViewModel', () => {

	const disposables = new DisposableStore();
	let mockChatSessionsService: MockChatSessionsService;
	let mockChatService: MockChatService;
	let viewModel: AgentSessionsViewModel;

	setup(() => {
		mockChatSessionsService = new MockChatSessionsService();
		mockChatService = new MockChatService();
	});

	teardown(() => {
		disposables.clear();
	});

	ensureNoDisposablesAreLeakedInTestSuite();

	test('should initialize with empty sessions', () => {
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		assert.strictEqual(viewModel.sessions.length, 0);
	});

	test('should resolve sessions from providers', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Test Session 1',
					description: 'Description 1',
					timing: { startTime: Date.now() }
				},
				{
					id: 'session-2',
					resource: URI.parse('test://session-2'),
					label: 'Test Session 2',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 2);
		assert.strictEqual(viewModel.sessions[0].id, 'session-1');
		assert.strictEqual(viewModel.sessions[0].label, 'Test Session 1');
		assert.strictEqual(viewModel.sessions[1].id, 'session-2');
		assert.strictEqual(viewModel.sessions[1].label, 'Test Session 2');
	});

	test('should resolve sessions from multiple providers', async () => {
		const provider1: IChatSessionItemProvider = {
			chatSessionType: 'type-1',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Session 1',
					timing: { startTime: Date.now() }
				}
			]
		};

		const provider2: IChatSessionItemProvider = {
			chatSessionType: 'type-2',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-2',
					resource: URI.parse('test://session-2'),
					label: 'Session 2',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider1);
		mockChatSessionsService.registerChatSessionItemProvider(provider2);

		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 2);
		assert.strictEqual(viewModel.sessions[0].id, 'session-1');
		assert.strictEqual(viewModel.sessions[1].id, 'session-2');
	});

	test('should fire onWillResolve and onDidResolve events', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => []
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		let willResolveFired = false;
		let didResolveFired = false;

		disposables.add(viewModel.onWillResolve(() => {
			willResolveFired = true;
			assert.strictEqual(didResolveFired, false, 'onDidResolve should not fire before onWillResolve completes');
		}));

		disposables.add(viewModel.onDidResolve(() => {
			didResolveFired = true;
			assert.strictEqual(willResolveFired, true, 'onWillResolve should fire before onDidResolve');
		}));

		await viewModel.resolve(undefined);

		assert.strictEqual(willResolveFired, true, 'onWillResolve should have fired');
		assert.strictEqual(didResolveFired, true, 'onDidResolve should have fired');
	});

	test('should fire onDidChangeSessions event after resolving', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Test Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		let sessionsChangedFired = false;
		disposables.add(viewModel.onDidChangeSessions(() => {
			sessionsChangedFired = true;
		}));

		await viewModel.resolve(undefined);

		assert.strictEqual(sessionsChangedFired, true, 'onDidChangeSessions should have fired');
	});

	test('should handle session with all properties', async () => {
		const startTime = Date.now();
		const endTime = startTime + 1000;

		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Test Session',
					description: new MarkdownString('**Bold** description'),
					status: ChatSessionStatus.Completed,
					tooltip: 'Session tooltip',
					iconPath: ThemeIcon.fromId('check'),
					timing: { startTime, endTime },
					statistics: { insertions: 10, deletions: 5 }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 1);
		const session = viewModel.sessions[0];
		assert.strictEqual(session.id, 'session-1');
		assert.strictEqual(session.label, 'Test Session');
		assert.ok(session.description instanceof MarkdownString);
		if (session.description instanceof MarkdownString) {
			assert.strictEqual(session.description.value, '**Bold** description');
		}
		assert.strictEqual(session.status, ChatSessionStatus.Completed);
		assert.strictEqual(session.timing.startTime, startTime);
		assert.strictEqual(session.timing.endTime, endTime);
		assert.deepStrictEqual(session.statistics, { insertions: 10, deletions: 5 });
	});

	test('should add default description for sessions without description', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Test Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 1);
		assert.ok(viewModel.sessions[0].description instanceof MarkdownString);
	});

	test('should filter out special session IDs', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'show-history',
					resource: URI.parse('test://show-history'),
					label: 'Show History',
					timing: { startTime: Date.now() }
				},
				{
					id: 'workbench.panel.chat.view.copilot',
					resource: URI.parse('test://copilot'),
					label: 'Copilot',
					timing: { startTime: Date.now() }
				},
				{
					id: 'valid-session',
					resource: URI.parse('test://valid'),
					label: 'Valid Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 1);
		assert.strictEqual(viewModel.sessions[0].id, 'valid-session');
	});

	test('should handle resolve with specific provider', async () => {
		const provider1: IChatSessionItemProvider = {
			chatSessionType: 'type-1',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Session 1',
					timing: { startTime: Date.now() }
				}
			]
		};

		const provider2: IChatSessionItemProvider = {
			chatSessionType: 'type-2',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-2',
					resource: URI.parse('test://session-2'),
					label: 'Session 2',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider1);
		mockChatSessionsService.registerChatSessionItemProvider(provider2);

		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		// First resolve all
		await viewModel.resolve(undefined);
		assert.strictEqual(viewModel.sessions.length, 2);

		// Now resolve only type-1
		await viewModel.resolve('type-1');
		// Should still have both sessions, but only type-1 was re-resolved
		assert.strictEqual(viewModel.sessions.length, 2);
	});

	test('should handle resolve with multiple specific providers', async () => {
		const provider1: IChatSessionItemProvider = {
			chatSessionType: 'type-1',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Session 1',
					timing: { startTime: Date.now() }
				}
			]
		};

		const provider2: IChatSessionItemProvider = {
			chatSessionType: 'type-2',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-2',
					resource: URI.parse('test://session-2'),
					label: 'Session 2',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider1);
		mockChatSessionsService.registerChatSessionItemProvider(provider2);

		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(['type-1', 'type-2']);

		assert.strictEqual(viewModel.sessions.length, 2);
	});

	test('should respond to onDidChangeItemsProviders event', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Test Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		const sessionsChangedPromise = Event.toPromise(viewModel.onDidChangeSessions);

		// Trigger event - this should automatically call resolve
		mockChatSessionsService.fireDidChangeItemsProviders(provider);

		// Wait for the sessions to be resolved
		await sessionsChangedPromise;

		assert.strictEqual(viewModel.sessions.length, 1);
	});

	test('should respond to onDidChangeAvailability event', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Test Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		const sessionsChangedPromise = Event.toPromise(viewModel.onDidChangeSessions);

		// Trigger event - this should automatically call resolve
		mockChatSessionsService.fireDidChangeAvailability();

		// Wait for the sessions to be resolved
		await sessionsChangedPromise;

		assert.strictEqual(viewModel.sessions.length, 1);
	});

	test('should respond to onDidChangeSessionItems event', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Test Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		const sessionsChangedPromise = Event.toPromise(viewModel.onDidChangeSessions);

		// Trigger event - this should automatically call resolve
		mockChatSessionsService.fireDidChangeSessionItems('test-type');

		// Wait for the sessions to be resolved
		await sessionsChangedPromise;

		assert.strictEqual(viewModel.sessions.length, 1);
	});

	test('should maintain provider reference in session view model', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Test Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 1);
		assert.strictEqual(viewModel.sessions[0].provider, provider);
		assert.strictEqual(viewModel.sessions[0].provider.chatSessionType, 'test-type');
	});

	test('should handle empty provider results', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => []
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 0);
	});

	test('should handle sessions with different statuses', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-failed',
					resource: URI.parse('test://session-failed'),
					label: 'Failed Session',
					status: ChatSessionStatus.Failed,
					timing: { startTime: Date.now() }
				},
				{
					id: 'session-completed',
					resource: URI.parse('test://session-completed'),
					label: 'Completed Session',
					status: ChatSessionStatus.Completed,
					timing: { startTime: Date.now() }
				},
				{
					id: 'session-inprogress',
					resource: URI.parse('test://session-inprogress'),
					label: 'In Progress Session',
					status: ChatSessionStatus.InProgress,
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 3);
		assert.strictEqual(viewModel.sessions[0].status, ChatSessionStatus.Failed);
		assert.strictEqual(viewModel.sessions[1].status, ChatSessionStatus.Completed);
		assert.strictEqual(viewModel.sessions[2].status, ChatSessionStatus.InProgress);
	});

	test('should replace sessions on re-resolve', async () => {
		let sessionCount = 1;

		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => {
				const sessions: IChatSessionItem[] = [];
				for (let i = 0; i < sessionCount; i++) {
					sessions.push({
						id: `session-${i}`,
						resource: URI.parse(`test://session-${i}`),
						label: `Session ${i}`,
						timing: { startTime: Date.now() }
					});
				}
				return sessions;
			}
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);
		assert.strictEqual(viewModel.sessions.length, 1);

		sessionCount = 3;
		await viewModel.resolve(undefined);
		assert.strictEqual(viewModel.sessions.length, 3);
	});

	test('should handle local agent session type specially', async () => {
		const provider: IChatSessionItemProvider = {
			chatSessionType: LOCAL_AGENT_SESSION_TYPE,
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'local-session',
					resource: ChatSessionUri.forSession(LOCAL_AGENT_SESSION_TYPE, 'local-session'),
					label: 'Local Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 1);
		assert.strictEqual(viewModel.sessions[0].provider.chatSessionType, LOCAL_AGENT_SESSION_TYPE);
	});

	test('should correctly construct resource URIs for sessions', async () => {
		const resource = URI.parse('custom://my-session/path');

		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => [
				{
					id: 'session-1',
					resource: resource,
					label: 'Test Session',
					timing: { startTime: Date.now() }
				}
			]
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		await viewModel.resolve(undefined);

		assert.strictEqual(viewModel.sessions.length, 1);
		assert.strictEqual(viewModel.sessions[0].resource.toString(), resource.toString());
	});

	test('should throttle multiple rapid resolve calls', async () => {
		let providerCallCount = 0;

		const provider: IChatSessionItemProvider = {
			chatSessionType: 'test-type',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => {
				providerCallCount++;
				return [
					{
						id: 'session-1',
						resource: URI.parse('test://session-1'),
						label: 'Test Session',
						timing: { startTime: Date.now() }
					}
				];
			}
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider);
		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		// Make multiple rapid resolve calls
		const resolvePromises = [
			viewModel.resolve(undefined),
			viewModel.resolve(undefined),
			viewModel.resolve(undefined)
		];

		await Promise.all(resolvePromises);

		// Should only call provider once due to throttling
		assert.strictEqual(providerCallCount, 1);
		assert.strictEqual(viewModel.sessions.length, 1);
	});

	test('should preserve sessions from non-resolved providers', async () => {
		let provider1CallCount = 0;
		let provider2CallCount = 0;

		const provider1: IChatSessionItemProvider = {
			chatSessionType: 'type-1',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => {
				provider1CallCount++;
				return [
					{
						id: 'session-1',
						resource: URI.parse('test://session-1'),
						label: `Session 1 (call ${provider1CallCount})`,
						timing: { startTime: Date.now() }
					}
				];
			}
		};

		const provider2: IChatSessionItemProvider = {
			chatSessionType: 'type-2',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => {
				provider2CallCount++;
				return [
					{
						id: 'session-2',
						resource: URI.parse('test://session-2'),
						label: `Session 2 (call ${provider2CallCount})`,
						timing: { startTime: Date.now() }
					}
				];
			}
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider1);
		mockChatSessionsService.registerChatSessionItemProvider(provider2);

		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		// First resolve all
		await viewModel.resolve(undefined);
		assert.strictEqual(viewModel.sessions.length, 2);
		assert.strictEqual(provider1CallCount, 1);
		assert.strictEqual(provider2CallCount, 1);
		const originalSession1Label = viewModel.sessions[0].label;

		// Now resolve only type-2
		await viewModel.resolve('type-2');

		// Should still have both sessions
		assert.strictEqual(viewModel.sessions.length, 2);
		// Provider 1 should not be called again
		assert.strictEqual(provider1CallCount, 1);
		// Provider 2 should be called again
		assert.strictEqual(provider2CallCount, 2);
		// Session 1 should be preserved with original label
		assert.strictEqual(viewModel.sessions.find(s => s.id === 'session-1')?.label, originalSession1Label);
	});

	test('should accumulate providers when resolve is called with different provider types', async () => {
		let resolveCount = 0;
		const resolvedProviders: (string | undefined)[] = [];

		const provider1: IChatSessionItemProvider = {
			chatSessionType: 'type-1',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => {
				resolveCount++;
				resolvedProviders.push('type-1');
				return [{
					id: 'session-1',
					resource: URI.parse('test://session-1'),
					label: 'Session 1',
					timing: { startTime: Date.now() }
				}];
			}
		};

		const provider2: IChatSessionItemProvider = {
			chatSessionType: 'type-2',
			onDidChangeChatSessionItems: Event.None,
			provideChatSessionItems: async () => {
				resolveCount++;
				resolvedProviders.push('type-2');
				return [{
					id: 'session-2',
					resource: URI.parse('test://session-2'),
					label: 'Session 2',
					timing: { startTime: Date.now() }
				}];
			}
		};

		mockChatSessionsService.registerChatSessionItemProvider(provider1);
		mockChatSessionsService.registerChatSessionItemProvider(provider2);

		viewModel = disposables.add(new AgentSessionsViewModel(
			mockChatSessionsService,
			mockChatService
		));

		// Call resolve with different types rapidly - they should accumulate
		const promise1 = viewModel.resolve('type-1');
		const promise2 = viewModel.resolve(['type-2']);

		await Promise.all([promise1, promise2]);

		// Both providers should be resolved
		assert.strictEqual(viewModel.sessions.length, 2);
	});
});

suite('AgentSessionsViewModel - Helper Functions', () => {
	const disposables = new DisposableStore();

	teardown(() => {
		disposables.clear();
	});

	ensureNoDisposablesAreLeakedInTestSuite();

	test('isLocalAgentSessionItem should identify local sessions', () => {
		const localSession: IAgentSessionViewModel = {
			provider: {
				chatSessionType: LOCAL_AGENT_SESSION_TYPE,
				onDidChangeChatSessionItems: Event.None,
				provideChatSessionItems: async () => []
			},
			id: 'local-1',
			resource: URI.parse('test://local-1'),
			label: 'Local',
			description: 'test',
			timing: { startTime: Date.now() }
		};

		const remoteSession: IAgentSessionViewModel = {
			provider: {
				chatSessionType: 'remote',
				onDidChangeChatSessionItems: Event.None,
				provideChatSessionItems: async () => []
			},
			id: 'remote-1',
			resource: URI.parse('test://remote-1'),
			label: 'Remote',
			description: 'test',
			timing: { startTime: Date.now() }
		};

		assert.strictEqual(isLocalAgentSessionItem(localSession), true);
		assert.strictEqual(isLocalAgentSessionItem(remoteSession), false);
	});

	test('isAgentSession should identify session view models', () => {
		const session: IAgentSessionViewModel = {
			provider: {
				chatSessionType: 'test',
				onDidChangeChatSessionItems: Event.None,
				provideChatSessionItems: async () => []
			},
			id: 'test-1',
			resource: URI.parse('test://test-1'),
			label: 'Test',
			description: 'test',
			timing: { startTime: Date.now() }
		};

		// Test with a session object
		assert.strictEqual(isAgentSession(session), true);

		// Test with a sessions container - pass as session to see it returns false
		const sessionOrContainer: IAgentSessionViewModel = session;
		assert.strictEqual(isAgentSession(sessionOrContainer), true);
	});

	test('isAgentSessionsViewModel should identify sessions view models', () => {
		const session: IAgentSessionViewModel = {
			provider: {
				chatSessionType: 'test',
				onDidChangeChatSessionItems: Event.None,
				provideChatSessionItems: async () => []
			},
			id: 'test-1',
			resource: URI.parse('test://test-1'),
			label: 'Test',
			description: 'test',
			timing: { startTime: Date.now() }
		};

		// Test with actual view model
		const actualViewModel = new AgentSessionsViewModel(new MockChatSessionsService(), new MockChatService());
		disposables.add(actualViewModel);
		assert.strictEqual(isAgentSessionsViewModel(actualViewModel), true);

		// Test with session object
		assert.strictEqual(isAgentSessionsViewModel(session), false);
	});
});
