// npx vitest run __tests__/extension.spec.ts

import type * as vscode from "vscode"
import type { AuthState } from "@roo-code/types"

vi.mock("vscode", async (importOriginal) => ({
	...(await importOriginal()),
	window: {
		createOutputChannel: vi.fn().mockReturnValue({
			appendLine: vi.fn(),
		}),
		createTextEditorDecorationType: vi.fn(),
		createStatusBarItem: vi.fn().mockReturnValue({
			text: "",
			tooltip: "",
			show: vi.fn(),
			hide: vi.fn(),
			dispose: vi.fn(),
		}),
		registerWebviewViewProvider: vi.fn(),
		registerUriHandler: vi.fn(),
		tabGroups: {
			onDidChangeTabs: vi.fn(),
		},
		onDidChangeActiveTextEditor: vi.fn(),
		onDidChangeVisibleTextEditors: vi.fn(),
		onDidChangeTextEditorSelection: vi.fn().mockReturnValue({ dispose: vi.fn() }),
	},
	workspace: {
		registerTextDocumentContentProvider: vi.fn(),
		getConfiguration: vi.fn().mockReturnValue({
			get: vi.fn().mockReturnValue([]),
			update: vi.fn().mockResolvedValue(undefined),
		}),
		createFileSystemWatcher: vi.fn().mockReturnValue({
			onDidCreate: vi.fn(),
			onDidChange: vi.fn(),
			onDidDelete: vi.fn(),
			dispose: vi.fn(),
		}),
		onDidChangeWorkspaceFolders: vi.fn(),
		onDidChangeConfiguration: vi.fn(),
		onDidChangeTextDocument: vi.fn(),
		onDidOpenTextDocument: vi.fn(),
		onDidCloseTextDocument: vi.fn(),
	},
	languages: {
		registerCodeActionsProvider: vi.fn(),
		registerCodeLensProvider: vi.fn().mockReturnValue({ dispose: vi.fn() }),
		registerInlineCompletionItemProvider: vi.fn().mockReturnValue({ dispose: vi.fn() }),
	},
	commands: {
		executeCommand: vi.fn(),
		registerCommand: vi.fn().mockReturnValue({ dispose: vi.fn() }),
		registerTextEditorCommand: vi.fn().mockReturnValue({ dispose: vi.fn() }),
	},
	env: {
		language: "en",
		appName: "roo-code",
	},
	ExtensionMode: {
		Production: 1,
	},
	ConfigurationTarget: {
		Global: 1,
		Workspace: 2,
		WorkspaceFolder: 3,
	},
	StatusBarAlignment: {
		Left: 1,
		Right: 2,
	},
	version: "1.80.0",
	RelativePattern: vi.fn().mockImplementation((base, pattern) => ({
		base,
		pattern,
	})),
	extensions: {
		all: [],
		getExtension: vi.fn().mockReturnValue({
			extensionUri: { fsPath: "/mock/extension/uri" },
		}),
	},
}))

vi.mock("@dotenvx/dotenvx", () => ({
	config: vi.fn(),
}))

// Mock fs so the extension module can safely check for optional .env.
vi.mock("fs", () => {
	const mockFs = {
		existsSync: vi.fn().mockReturnValue(false),
	}
	return {
		default: mockFs,
		existsSync: mockFs.existsSync,
	}
})

const mockCloudServiceInstance = {
	off: vi.fn(),
	on: vi.fn(),
	getUserInfo: vi.fn().mockReturnValue(null),
	isTaskSyncEnabled: vi.fn().mockReturnValue(false),
	authService: {
		getSessionToken: vi.fn().mockReturnValue("test-session-token"),
	},
}

vi.mock("@roo-code/cloud", () => ({
	CloudService: {
		createInstance: vi.fn(),
		hasInstance: vi.fn().mockReturnValue(true),
		get instance() {
			return mockCloudServiceInstance
		},
	},
	getRooCodeApiUrl: vi.fn().mockReturnValue("https://app.roocode.com"),
}))

vi.mock("@roo-code/telemetry", () => ({
	TelemetryService: {
		createInstance: vi.fn().mockReturnValue({
			register: vi.fn(),
			setProvider: vi.fn(),
			shutdown: vi.fn(),
		}),
		get instance() {
			return {
				register: vi.fn(),
				setProvider: vi.fn(),
				shutdown: vi.fn(),
			}
		},
	},
	PostHogTelemetryClient: vi.fn(),
}))

vi.mock("../utils/outputChannelLogger", () => ({
	createOutputChannelLogger: vi.fn().mockReturnValue(vi.fn()),
	createDualLogger: vi.fn().mockReturnValue(vi.fn()),
}))

vi.mock("../shared/package", () => ({
	Package: {
		name: "test-extension",
		outputChannel: "Test Output",
		version: "1.0.0",
	},
}))

vi.mock("../shared/language", () => ({
	formatLanguage: vi.fn().mockReturnValue("en"),
}))

vi.mock("../core/config/ContextProxy", () => ({
	ContextProxy: {
		getInstance: vi.fn().mockResolvedValue({
			getValue: vi.fn(),
			setValue: vi.fn(),
			getValues: vi.fn().mockReturnValue({}),
			getProviderSettings: vi.fn().mockReturnValue({}),
		}),
	},
}))

vi.mock("../integrations/editor/DiffViewProvider", () => ({
	DIFF_VIEW_URI_SCHEME: "test-diff-scheme",
}))

vi.mock("../integrations/terminal/TerminalRegistry", () => ({
	TerminalRegistry: {
		initialize: vi.fn(),
		cleanup: vi.fn(),
	},
}))

vi.mock("../services/mcp/McpServerManager", () => ({
	McpServerManager: {
		cleanup: vi.fn().mockResolvedValue(undefined),
		getInstance: vi.fn().mockResolvedValue(null),
		unregisterProvider: vi.fn(),
	},
}))

vi.mock("../services/code-index/manager", () => ({
	CodeIndexManager: {
		getInstance: vi.fn().mockReturnValue(null),
	},
}))

vi.mock("../services/mdm/MdmService", () => ({
	MdmService: {
		createInstance: vi.fn().mockResolvedValue(null),
	},
}))

vi.mock("../utils/migrateSettings", () => ({
	migrateSettings: vi.fn().mockResolvedValue(undefined),
}))

vi.mock("../utils/autoImportSettings", () => ({
	autoImportSettings: vi.fn().mockResolvedValue(undefined),
}))

vi.mock("../extension/api", () => ({
	API: vi.fn().mockImplementation(() => ({})),
}))

vi.mock("../activate", () => ({
	handleUri: vi.fn(),
	registerCommands: vi.fn(),
	registerCodeActions: vi.fn(),
	registerTerminalActions: vi.fn(),
	CodeActionProvider: vi.fn().mockImplementation(() => ({
		providedCodeActionKinds: [],
	})),
}))

vi.mock("../i18n", () => ({
	initializeI18n: vi.fn(),
	t: vi.fn((key) => key),
}))

// Mock ClineProvider
vi.mock("../core/webview/ClineProvider", async () => {
	const mockInstance = {
		resolveWebviewView: vi.fn(),
		postMessageToWebview: vi.fn(),
		postStateToWebview: vi.fn(),
		postStateToWebviewWithoutClineMessages: vi.fn(),
		getState: vi.fn().mockResolvedValue({}),
		initializeCloudProfileSyncWhenReady: vi.fn().mockResolvedValue(undefined),
		providerSettingsManager: {},
		contextProxy: { getGlobalState: vi.fn() },
		customModesManager: {},
		upsertProviderProfile: vi.fn().mockResolvedValue(undefined),
	}
	return {
		ClineProvider: Object.assign(
			vi.fn().mockImplementation(() => mockInstance),
			{
				// Static method used by extension.ts
				getVisibleInstance: vi.fn().mockReturnValue(mockInstance),
				sideBarId: "costrict.SidebarProvider",
			},
		),
	}
})

// Mock modelCache to prevent network requests during module loading
const mockRefreshModels = vi.fn().mockResolvedValue({})
vi.mock("../api/providers/fetchers/modelCache", () => ({
	flushModels: vi.fn(),
	getModels: vi.fn().mockResolvedValue([]),
	initializeModelCacheRefresh: vi.fn(),
	refreshModels: mockRefreshModels,
}))

describe("extension.ts", () => {
	let mockContext: vscode.ExtensionContext
	let authStateChangedHandler:
		| ((data: { state: AuthState; previousState: AuthState }) => void | Promise<void>)
		| undefined

	beforeEach(() => {
		vi.clearAllMocks()

		mockContext = {
			extensionPath: "/test/path",
			globalState: {
				get: vi.fn().mockReturnValue(undefined),
				update: vi.fn(),
			},
			subscriptions: [],
		} as unknown as vscode.ExtensionContext

		authStateChangedHandler = undefined
	})

	test("does not call dotenvx.config when optional .env does not exist", async () => {
		// Reset modules to test module-level initialization code
		vi.resetModules()

		// Re-mock the modules BEFORE importing extension
		vi.doMock("fs", () => ({
			default: { existsSync: vi.fn().mockReturnValue(false) },
			existsSync: vi.fn().mockReturnValue(false),
		}))

		const dotenvxConfigMock = vi.fn()
		vi.doMock("@dotenvx/dotenvx", () => ({
			config: dotenvxConfigMock,
		}))

		// Import extension - this will execute the top-level code
		// which should NOT call dotenvx.config when .env doesn't exist
		await import("../extension")

		// Add a small delay to ensure module initialization is complete
		await new Promise((resolve) => setTimeout(resolve, 100))

		// Verify dotenvx.config was not called
		expect(dotenvxConfigMock).not.toHaveBeenCalled()
	}, 120000)

	test("calls dotenvx.config when optional .env exists", async () => {
		// Reset modules to test module-level initialization code
		vi.resetModules()

		// Re-mock the modules BEFORE importing extension
		vi.doMock("fs", () => ({
			default: { existsSync: vi.fn().mockReturnValue(true) },
			existsSync: vi.fn().mockReturnValue(true),
		}))

		const dotenvxConfigMock = vi.fn()
		vi.doMock("@dotenvx/dotenvx", () => ({
			config: dotenvxConfigMock,
		}))

		// Import extension - this will execute the top-level code
		// which should call dotenvx.config when .env exists
		await import("../extension")

		// Verify dotenvx.config was called exactly once
		expect(dotenvxConfigMock).toHaveBeenCalledTimes(1)
	}, 60000)

	//	describe("Roo model cache refresh on auth state change (ROO-202)", () => {
	//		beforeEach(() => {
	//			vi.resetModules()
	//			mockRefreshModels.mockClear()
	//		})
	//	})
	// 	test("refreshModels is called with session token when auth state changes to active-session", async () => {
	// 		const mockAuthService = {
	// 			getSessionToken: vi.fn().mockReturnValue("test-session-token"),
	// 		}

	// 		const { CloudService } = await import("@roo-code/cloud")

	// 		vi.mocked(CloudService.createInstance).mockImplementation(async (_context, _logger, handlers) => {
	// 			if (handlers?.["auth-state-changed"]) {
	// 				authStateChangedHandler = handlers["auth-state-changed"]
	// 			}
	// 			return {
	// 				off: vi.fn(),
	// 				on: vi.fn(),
	// 				telemetryClient: null,
	// 				authService: mockAuthService,
	// 				hasActiveSession: vi.fn().mockReturnValue(false),
	// 			} as any
	// 		})

	// 		vi.mocked(CloudService.hasInstance).mockReturnValue(true)

	// 		// Activate the extension
	// 		const { activate } = await import("../extension")
	// 		await activate(mockContext)

	// 		// Clear any calls during activation
	// 		mockRefreshModels.mockClear()

	// 		// Trigger active-session state
	// 		await authStateChangedHandler!({
	// 			state: "active-session" as AuthState,
	// 			previousState: "logged-out" as AuthState,
	// 		})

	// 		// Verify refreshModels was called with correct parameters including session token
	// 		expect(mockRefreshModels).toHaveBeenCalledWith({
	// 			provider: "roo",
	// 			baseUrl: expect.any(String),
	// 			apiKey: "test-session-token",
	// 		})
	// 	})

	// 	test("flushModels is called when auth state changes to logged-out", async () => {
	// 		const { flushModels } = await import("../api/providers/fetchers/modelCache")
	// 		const { CloudService } = await import("@roo-code/cloud")

	// 		vi.mocked(CloudService.createInstance).mockImplementation(async (_context, _logger, handlers) => {
	// 			if (handlers?.["auth-state-changed"]) {
	// 				authStateChangedHandler = handlers["auth-state-changed"]
	// 			}
	// 			return {
	// 				off: vi.fn(),
	// 				on: vi.fn(),
	// 				telemetryClient: null,
	// 				authService: null,
	// 				hasActiveSession: vi.fn().mockReturnValue(false),
	// 			} as any
	// 		})

	// 		vi.mocked(CloudService.hasInstance).mockReturnValue(true)

	// 		// Activate the extension
	// 		const { activate } = await import("../extension")
	// 		await activate(mockContext)

	// 		// Trigger logged-out state
	// 		await authStateChangedHandler!({
	// 			state: "logged-out" as AuthState,
	// 			previousState: "active-session" as AuthState,
	// 		})

	// 		// Verify flushModels was called to clear the cache on logout
	// 		expect(flushModels).toHaveBeenCalledWith("roo", false)
	// 	})
	// })
})
