/**
 * Comprehensive VS Code API mock for SnapBack extension testing
 * Provides realistic mocks for all VS Code APIs used by the extension
 *
 * ESM version - converted from CommonJS for vitest compatibility
 */

import { vi } from "vitest";

// Mock event emitter for VS Code events
class MockEventEmitter {
	constructor() {
		this._listeners = [];
		// VS Code's EventEmitter exposes an .event property that is a function
		this.event = (listener) => {
			this._listeners.push(listener);
			return {
				dispose: () => {
					const idx = this._listeners.indexOf(listener);
					if (idx >= 0) {
						this._listeners.splice(idx, 1);
					}
				},
			};
		};
	}

	fire(data) {
		for (const listener of this._listeners) {
			listener(data);
		}
	}

	dispose() {
		this._listeners = [];
	}
}

// Mock TreeItem for tree views
class MockTreeItem {
	constructor(label, collapsibleState = 0) {
		this.label = label;
		this.collapsibleState = collapsibleState;
		this.children = [];
		this.contextValue = "";
		this.tooltip = "";
		this.description = "";
		this.iconPath = null;
		this.command = null;
	}
}

// Mock TreeDataProvider
class MockTreeDataProvider {
	constructor() {
		this.data = [];
		this._onDidChangeTreeData = new MockEventEmitter();
		this.onDidChangeTreeData = this._onDidChangeTreeData.event;
	}

	getTreeItem(element) {
		return element;
	}

	getChildren(element) {
		if (!element) {
			return Promise.resolve(this.data);
		}
		return Promise.resolve(element.children || []);
	}

	refresh() {
		this._onDidChangeTreeData.fire();
	}
}

// Mock WebviewView
class MockWebviewView {
	constructor() {
		this.webview = {
			html: "",
			options: {},
			cspSource: "vscode-resource:",
			asWebviewUri: (uri) => uri,
			postMessage: vi.fn(),
			onDidReceiveMessage: vi.fn(),
		};
		this.visible = true;
		this.viewType = "";
		this.title = "";
		this.description = "";
		this.onDidDispose = vi.fn();
		this.onDidChangeVisibility = vi.fn();
	}

	show(_preserveFocus) {
		this.visible = true;
	}

	dispose() {
		this.visible = false;
		if (this.onDidDispose) {
			this.onDidDispose();
		}
	}
}

// Mock StatusBarItem
class MockStatusBarItem {
	constructor() {
		this.text = "";
		this.tooltip = "";
		this.command = "";
		this.color = "";
		this.backgroundColor = null;
		this.priority = 0;
		this.alignment = 1; // StatusBarAlignment.Left
		this.accessibilityInformation = null;
	}

	show() {
		this.visible = true;
	}

	hide() {
		this.visible = false;
	}

	dispose() {
		this.visible = false;
	}
}

// Mock ExtensionContext
class MockExtensionContext {
	constructor() {
		this.subscriptions = [];
		this.workspaceState = new MockMemento();
		this.globalState = new MockMemento();
		this.secrets = new MockSecretStorage();
		this.extensionUri = { scheme: "file", path: "/test/extension" };
		this.extensionPath = "/test/extension";
		this.storagePath = "/test/storage";
		this.globalStoragePath = "/test/global-storage";
		this.logPath = "/test/logs";
		this.extensionMode = 1; // ExtensionMode.Development
		this.environment = {
			appName: "Visual Studio Code - Insiders",
			appRoot: "/test/vscode",
			language: "en",
			sessionId: "test-session-id",
			machineId: "test-machine-id",
		};
	}
}

// Mock Memento (workspace/global state)
class MockMemento {
	constructor() {
		this.storage = new Map();
	}

	get(key, defaultValue) {
		return this.storage.get(key) ?? defaultValue;
	}

	update(key, value) {
		this.storage.set(key, value);
		return Promise.resolve();
	}

	keys() {
		return Array.from(this.storage.keys());
	}
}

// Mock Secret Storage
class MockSecretStorage {
	constructor() {
		this.secrets = new Map();
		this.onDidChange = vi.fn();
	}

	get(key) {
		return Promise.resolve(this.secrets.get(key));
	}

	store(key, value) {
		this.secrets.set(key, value);
		return Promise.resolve();
	}

	delete(key) {
		this.secrets.delete(key);
		return Promise.resolve();
	}
}

// Mock FileSystemWatcher
class MockFileSystemWatcher extends MockEventEmitter {
	constructor() {
		super();
		this.ignoreCreateEvents = false;
		this.ignoreChangeEvents = false;
		this.ignoreDeleteEvents = false;
	}

	dispose() {
		this._listeners = [];
	}
}

// Mock TextDocument
class MockTextDocument {
	constructor(uri = { scheme: "file", path: "/test/file.ts" }, content = "") {
		this.uri = uri;
		this.fileName = uri.path;
		this.isUntitled = false;
		this.languageId = "typescript";
		this.version = 1;
		this.isDirty = false;
		this.isClosed = false;
		this.eol = 1; // EndOfLine.LF
		this.lineCount = content.split("\n").length;
		this._content = content;
	}

	save() {
		this.isDirty = false;
		return Promise.resolve(true);
	}

	getText(_range) {
		return this._content;
	}

	getWordRangeAtPosition(_position, _regex) {
		return null;
	}

	validateRange(range) {
		return range;
	}

	validatePosition(position) {
		return position;
	}

	offsetAt(_position) {
		return 0;
	}

	positionAt(_offset) {
		return { line: 0, character: 0 };
	}

	lineAt(_lineOrPosition) {
		return {
			lineNumber: 0,
			text: "",
			range: {
				start: { line: 0, character: 0 },
				end: { line: 0, character: 0 },
			},
			rangeIncludingLineBreak: {
				start: { line: 0, character: 0 },
				end: { line: 0, character: 0 },
			},
			firstNonWhitespaceCharacterIndex: 0,
			isEmptyOrWhitespace: true,
		};
	}
}

// Mock TimelineItem
class MockTimelineItem {
	constructor(label, timestamp) {
		this.label = label;
		this.timestamp = timestamp;
		this.id = undefined;
		this.description = undefined;
		this.iconPath = undefined;
		this.command = undefined;
	}
}

// Mock CodeLens
class MockCodeLens {
	constructor(range, command) {
		this.range = range;
		this.command = command;
		this.isResolved = command !== undefined;
	}
}

// Mock Hover
class MockHover {
	constructor(contents, range) {
		this.contents = Array.isArray(contents) ? contents : [contents];
		this.range = range;
	}
}

// Mock QuickPickItem
class MockQuickPickItem {
	constructor(label, description, detail) {
		this.label = label;
		this.description = description;
		this.detail = detail;
		this.picked = false;
		this.alwaysShow = false;
	}
}

// Main VS Code API mock
const vscode = {
	// Enums
	TreeItemCollapsibleState: {
		None: 0,
		Collapsed: 1,
		Expanded: 2,
	},

	QuickPickItemKind: {
		Separator: 1,
		Default: 0,
	},

	StatusBarAlignment: {
		Left: 1,
		Right: 2,
	},

	ExtensionMode: {
		Production: 0,
		Development: 1,
		Test: 2,
	},

	ProgressLocation: {
		SourceControl: 1,
		Window: 10,
		Notification: 15,
	},

	FileType: {
		Unknown: 0,
		File: 1,
		Directory: 2,
		SymbolicLink: 64,
	},

	DiagnosticSeverity: {
		Error: 0,
		Warning: 1,
		Information: 2,
		Hint: 3,
	},

	ConfigurationTarget: {
		Global: 1,
		Workspace: 2,
		WorkspaceFolder: 3,
	},

	ViewColumn: {
		Active: -1,
		Beside: -2,
		One: 1,
		Two: 2,
		Three: 3,
	},

	EndOfLine: {
		LF: 1,
		CRLF: 2,
	},

	TextEditorRevealType: {
		Default: 0,
		InCenter: 1,
		InCenterIfOutsideViewport: 2,
		AtTop: 3,
	},

	// Window API
	window: {
		showInformationMessage: vi.fn().mockResolvedValue(undefined),
		showWarningMessage: vi.fn().mockResolvedValue(undefined),
		showErrorMessage: vi.fn().mockResolvedValue(undefined),
		showQuickPick: vi.fn().mockResolvedValue(undefined),
		showInputBox: vi.fn().mockResolvedValue(undefined),
		showSaveDialog: vi.fn().mockResolvedValue(undefined),
		showOpenDialog: vi.fn().mockResolvedValue(undefined),
		showWorkspaceFolderPick: vi.fn().mockResolvedValue(undefined),
		setStatusBarMessage: vi.fn((_message, _hideAfterTimeout) => ({
			dispose: vi.fn(),
		})),

		createStatusBarItem: vi.fn(() => new MockStatusBarItem()),
		createQuickPick: vi.fn(() => ({
			items: [],
			title: "",
			placeholder: "",
			show: vi.fn(),
			hide: vi.fn(),
			dispose: vi.fn(),
			onDidAccept: vi.fn(() => ({ dispose: vi.fn() })),
			onDidHide: vi.fn(() => ({ dispose: vi.fn() })),
			matchOnDescription: false,
			matchOnDetail: false,
			busy: false,
		})),
		createOutputChannel: vi.fn((name, _options) => ({
			name,
			append: vi.fn(),
			appendLine: vi.fn(),
			clear: vi.fn(),
			show: vi.fn(),
			hide: vi.fn(),
			dispose: vi.fn(),
			replace: vi.fn(),
			// LogOutputChannel methods (when options.log is true)
			trace: vi.fn(),
			debug: vi.fn(),
			info: vi.fn(),
			warn: vi.fn(),
			error: vi.fn(),
			logLevel: 2, // Info level
		})),
		createTreeView: vi.fn((viewId, options) => ({
			viewId,
			options,
			visible: true,
			title: options.treeDataProvider?.title || "",
			message: "",
			description: "",
			selection: [],
			reveal: vi.fn(),
			dispose: vi.fn(),
			onDidChangeSelection: vi.fn(),
			onDidChangeVisibility: vi.fn(),
			onDidCollapseElement: vi.fn(),
			onDidExpandElement: vi.fn(),
		})),
		createWebviewPanel: vi.fn((viewType, title, showOptions, options) => ({
			viewType,
			title,
			webview: {
				html: "",
				options: options || {},
				cspSource: "vscode-resource:",
				asWebviewUri: (uri) => uri,
				postMessage: vi.fn().mockResolvedValue(true),
				onDidReceiveMessage: new MockEventEmitter().event,
			},
			options: options || {},
			visible: true,
			active: true,
			viewColumn: typeof showOptions === "number" ? showOptions : showOptions?.viewColumn || 1,
			onDidChangeViewState: new MockEventEmitter().event,
			onDidDispose: new MockEventEmitter().event,
			reveal: vi.fn(),
			dispose: vi.fn(),
		})),
		registerTreeDataProvider: vi.fn(() => ({ dispose: vi.fn() })),
		registerWebviewViewProvider: vi.fn(() => ({ dispose: vi.fn() })),
		registerFileDecorationProvider: vi.fn(() => ({ dispose: vi.fn() })),
		withProgress: vi.fn((_options, task) => {
			// Execute the task with a mock progress reporter
			const progress = {
				report: vi.fn(),
			};
			const token = {
				isCancellationRequested: false,
				onCancellationRequested: vi.fn(),
			};
			return Promise.resolve(task(progress, token));
		}),

		activeTextEditor: null,
		visibleTextEditors: [],
		terminals: [],

		onDidChangeActiveTextEditor: vi.fn(),
		onDidChangeVisibleTextEditors: vi.fn(),
		onDidChangeWindowState: vi.fn(),
		onDidChangeTextEditorSelection: vi.fn(),
		onDidChangeTextEditorViewColumn: vi.fn(),
		onDidChangeTextEditorVisibleRanges: vi.fn(),

		// Terminal API
		createTerminal: vi.fn((_options) => ({
			name: _options?.name ?? "Terminal",
			processId: Promise.resolve(12345),
			shellIntegration: undefined,
			show: vi.fn(),
			hide: vi.fn(),
			sendText: vi.fn(),
			dispose: vi.fn(),
		})),
		// Shell Integration API (VS Code 1.93+)
		onDidChangeTerminalShellIntegration: vi.fn(() => ({ dispose: vi.fn() })),
		onDidEndTerminalShellExecution: vi.fn(() => ({ dispose: vi.fn() })),

		// Tab Groups API
		tabGroups: {
			all: [],
			onDidChangeTabs: new MockEventEmitter().event,
			close: vi.fn(() => Promise.resolve(true)),
		},
	},

	// Workspace API
	workspace: {
		workspaceFolders: [],
		name: "Test Workspace",
		workspaceFile: null,

		getConfiguration: vi.fn((_section) => ({
			get: vi.fn((_key, defaultValue) => defaultValue),
			update: vi.fn().mockResolvedValue(undefined),
			inspect: vi.fn(() => ({})),
			has: vi.fn(() => false),
		})),

		getWorkspaceFolder: vi.fn((uri) => {
			if (!uri) {
				return undefined;
			}
			return {
				uri: uri,
				name: "Test Workspace",
				index: 0,
			};
		}),

		applyEdit: vi.fn().mockResolvedValue(true),

		// FileSystem API
		fs: {
			readFile: vi.fn().mockResolvedValue(new Uint8Array()),
			writeFile: vi.fn().mockResolvedValue(undefined),
			delete: vi.fn().mockResolvedValue(undefined),
			rename: vi.fn().mockResolvedValue(undefined),
			copy: vi.fn().mockResolvedValue(undefined),
			createDirectory: vi.fn().mockResolvedValue(undefined),
			readDirectory: vi.fn().mockResolvedValue([]),
			stat: vi.fn().mockResolvedValue({
				type: 1, // FileType.File
				ctime: Date.now(),
				mtime: Date.now(),
				size: 0,
			}),
			isWritableFileSystem: vi.fn().mockReturnValue(true),
		},

		createFileSystemWatcher: vi.fn(() => new MockFileSystemWatcher()),
		findFiles: vi.fn().mockResolvedValue([]),
		saveAll: vi.fn().mockResolvedValue(true),
		openTextDocument: vi.fn().mockResolvedValue(new MockTextDocument()),

		// Add the TimelineProvider registration function
		registerTimelineProvider: vi.fn((_selector, _provider) => ({
			dispose: vi.fn(),
		})),

		onDidChangeConfiguration: vi.fn(),
		onDidChangeWorkspaceFolders: vi.fn(),
		onDidCreateFiles: vi.fn(),
		onDidDeleteFiles: vi.fn(),
		onDidRenameFiles: vi.fn(),
		onDidSaveTextDocument: vi.fn(),
		onDidOpenTextDocument: vi.fn(),
		onDidCloseTextDocument: vi.fn(),
		onDidChangeTextDocument: vi.fn(),
		onWillSaveTextDocument: vi.fn(),
	},

	// Commands API
	commands: {
		registerCommand: vi.fn((_command, _callback) => ({
			dispose: vi.fn(),
		})),
		registerTextEditorCommand: vi.fn((_command, _callback) => ({
			dispose: vi.fn(),
		})),
		executeCommand: vi.fn().mockResolvedValue(undefined),
		getCommands: vi.fn().mockResolvedValue([]),
	},

	// Languages API
	languages: {
		registerCodeActionsProvider: vi.fn(() => ({ dispose: vi.fn() })),
		registerCompletionItemProvider: vi.fn(() => ({ dispose: vi.fn() })),
		registerHoverProvider: vi.fn(() => ({ dispose: vi.fn() })),
		registerDefinitionProvider: vi.fn(() => ({ dispose: vi.fn() })),
		registerDocumentFormattingEditProvider: vi.fn(() => ({
			dispose: vi.fn(),
		})),
		createDiagnosticCollection: vi.fn(() => ({
			set: vi.fn(),
			delete: vi.fn(),
			clear: vi.fn(),
			forEach: vi.fn(),
			get: vi.fn(),
			has: vi.fn(),
			dispose: vi.fn(),
		})),
	},

	// Extensions API
	extensions: {
		getExtension: vi.fn(),
		all: [],
		onDidChange: vi.fn(),
	},

	// Debug API
	debug: {
		activeDebugSession: null,
		activeDebugConsole: null,
		breakpoints: [],
		onDidChangeActiveDebugSession: vi.fn(),
		onDidStartDebugSession: vi.fn(),
		onDidReceiveDebugSessionCustomEvent: vi.fn(),
		onDidTerminateDebugSession: vi.fn(),
		onDidChangeBreakpoints: vi.fn(),
		registerDebugConfigurationProvider: vi.fn(() => ({
			dispose: vi.fn(),
		})),
		registerDebugAdapterDescriptorFactory: vi.fn(() => ({
			dispose: vi.fn(),
		})),
		startDebugging: vi.fn().mockResolvedValue(true),
		stopDebugging: vi.fn().mockResolvedValue(undefined),
		addBreakpoints: vi.fn(),
		removeBreakpoints: vi.fn(),
	},

	// Tasks API
	tasks: {
		registerTaskProvider: vi.fn(() => ({ dispose: vi.fn() })),
		fetchTasks: vi.fn().mockResolvedValue([]),
		executeTask: vi.fn().mockResolvedValue({}),
		onDidStartTask: vi.fn(),
		onDidEndTask: vi.fn(),
		onDidStartTaskProcess: vi.fn(),
		onDidEndTaskProcess: vi.fn(),
	},

	// Environment API
	env: {
		appName: "Visual Studio Code - Insiders",
		appRoot: "/test/vscode",
		language: "en",
		clipboard: {
			readText: vi.fn().mockResolvedValue(""),
			writeText: vi.fn().mockResolvedValue(undefined),
		},
		machineId: "test-machine-id",
		sessionId: "test-session-id",
		openExternal: vi.fn().mockResolvedValue(true),
		asExternalUri: vi.fn().mockResolvedValue(null),
	},

	// Authentication API
	authentication: {
		registerAuthenticationProvider: vi.fn(() => ({ dispose: vi.fn() })),
		getSession: vi.fn(() => Promise.resolve(null)),
		onDidChangeSessions: new MockEventEmitter().event,
	},

	// URI utilities
	Uri: {
		file: vi.fn((path) => ({
			scheme: "file",
			path,
			fsPath: path,
			authority: "",
			query: "",
			fragment: "",
			toString: () => `file://${path}`,
			toJSON: () => ({ scheme: "file", path, fsPath: path }),
			with: (change) => ({
				scheme: change.scheme || "file",
				path: change.path || path,
				fsPath: change.path || path,
				toString: () => `file://${change.path || path}`,
			}),
		})),
		parse: vi.fn((uri) => ({
			scheme: "file",
			path: uri,
			fsPath: uri,
			authority: "",
			query: "",
			fragment: "",
			toString: () => uri,
		})),
		joinPath: vi.fn((base, ...segments) => {
			const newPath = `${base.path}/${segments.join("/")}`;
			return {
				scheme: base.scheme,
				path: newPath,
				fsPath: newPath,
				authority: "",
				query: "",
				fragment: "",
				toString: () => `${base.scheme}://${newPath}`,
			};
		}),
	},

	// Classes and constructors
	EventEmitter: MockEventEmitter,
	TreeItem: MockTreeItem,
	TreeDataProvider: MockTreeDataProvider,
	WebviewView: MockWebviewView,
	StatusBarItem: MockStatusBarItem,
	ExtensionContext: MockExtensionContext,
	Memento: MockMemento,
	FileSystemWatcher: MockFileSystemWatcher,
	TextDocument: MockTextDocument,
	TimelineItem: MockTimelineItem,
	CodeLens: MockCodeLens,
	Hover: MockHover,
	QuickPickItem: MockQuickPickItem,

	// ThemeColor for UI theming
	ThemeColor: class {
		constructor(id) {
			this.id = id;
		}
	},

	// ThemeIcon for icons
	ThemeIcon: class {
		constructor(id, color) {
			this.id = id;
			this.color = color;
		}
		static get File() {
			return new this("file");
		}
		static get Folder() {
			return new this("folder");
		}
	},

	// Disposable
	Disposable: class {
		constructor(callback) {
			this.callback = callback;
		}
		dispose() {
			if (this.callback) {
				this.callback();
			}
		}
		static from(...disposables) {
			return new vscode.Disposable(() => {
				for (const d of disposables) {
					d.dispose();
				}
			});
		}
	},

	// Position and Range
	Position: class {
		constructor(line, character) {
			this.line = line;
			this.character = character;
		}
	},

	Range: class {
		constructor(startLine, startCharacter, endLine, endCharacter) {
			this.start = new vscode.Position(startLine, startCharacter);
			this.end = new vscode.Position(endLine, endCharacter);
		}
	},

	// MarkdownString for tooltips
	MarkdownString: class {
		constructor(value = "") {
			this.value = value;
			this.isTrusted = false;
			this.supportThemeIcons = false;
			this.supportHtml = false;
		}
		appendMarkdown(markdown) {
			this.value += markdown;
			return this;
		}
		appendText(text) {
			this.value += text;
			return this;
		}
		appendCodeblock(code, language = "") {
			this.value += `
\`\`\`${language}
${code}
\`\`\`
`;
			return this;
		}
	},

	// FileDecoration for file decoration provider
	FileDecoration: class {
		constructor(badge, tooltip, color) {
			this.badge = badge;
			this.tooltip = tooltip;
			this.color = color;
			this.propagate = false;
		}
	},
};

// Selection (defined after vscode is fully constructed)
vscode.Selection = class extends vscode.Range {
	constructor(anchorLine, anchorCharacter, activeLine, activeCharacter) {
		super(anchorLine, anchorCharacter, activeLine, activeCharacter);
		this.anchor = new vscode.Position(anchorLine, anchorCharacter);
		this.active = new vscode.Position(activeLine, activeCharacter);
	}
};

// Export as default
export default vscode;

// Also export all members as named exports for ESM compatibility
// This allows both `import vscode from 'vscode'` and `import * as vscode from 'vscode'`
export const {
	// Enums
	TreeItemCollapsibleState,
	QuickPickItemKind,
	StatusBarAlignment,
	ExtensionMode,
	ProgressLocation,
	FileType,
	DiagnosticSeverity,
	ConfigurationTarget,
	ViewColumn,
	EndOfLine,
	TextEditorRevealType,
	// APIs
	window,
	workspace,
	commands,
	languages,
	extensions,
	debug,
	tasks,
	env,
	authentication,
	Uri,
	// Classes
	EventEmitter,
	TreeItem,
	TreeDataProvider,
	WebviewView,
	StatusBarItem,
	ExtensionContext,
	Memento,
	FileSystemWatcher,
	TextDocument,
	TimelineItem,
	CodeLens,
	Hover,
	QuickPickItem,
	ThemeColor,
	ThemeIcon,
	Disposable,
	Position,
	Range,
	MarkdownString,
	FileDecoration,
	Selection,
} = vscode;
