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

import { Disposable } from '../../../../../base/common/lifecycle.js';
import { dirname, extUriBiasedIgnorePathCase } from '../../../../../base/common/resources.js';
import { URI } from '../../../../../base/common/uri.js';
import { IFileDialogService } from '../../../../../platform/dialogs/common/dialogs.js';
import { IFileService } from '../../../../../platform/files/common/files.js';
import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js';
import { ILabelService } from '../../../../../platform/label/common/label.js';
import { IStorageService } from '../../../../../platform/storage/common/storage.js';
import { IWorkbenchContribution } from '../../../../common/contributions.js';
import { ChatExternalPathConfirmationContribution } from '../../common/tools/builtinTools/chatExternalPathConfirmation.js';
import { ChatUrlFetchingConfirmationContribution } from '../../common/tools/builtinTools/chatUrlFetchingConfirmation.js';
import { ILanguageModelToolsConfirmationService } from '../../common/tools/languageModelToolsConfirmationService.js';
import { ILanguageModelToolsService } from '../../common/tools/languageModelToolsService.js';
import { InternalFetchWebPageToolId } from '../../common/tools/builtinTools/tools.js';
import { FetchWebPageTool, FetchWebPageToolData, IFetchWebPageToolParams } from './fetchPageTool.js';

export class NativeBuiltinToolsContribution extends Disposable implements IWorkbenchContribution {

	static readonly ID = 'chat.nativeBuiltinTools';

	constructor(
		@ILanguageModelToolsService toolsService: ILanguageModelToolsService,
		@IInstantiationService instantiationService: IInstantiationService,
		@ILanguageModelToolsConfirmationService confirmationService: ILanguageModelToolsConfirmationService,
		@IFileService fileService: IFileService,
		@IStorageService storageService: IStorageService,
		@IFileDialogService fileDialogService: IFileDialogService,
		@ILabelService labelService: ILabelService,
	) {
		super();

		const editTool = instantiationService.createInstance(FetchWebPageTool);
		this._register(toolsService.registerTool(FetchWebPageToolData, editTool));

		this._register(confirmationService.registerConfirmationContribution(
			InternalFetchWebPageToolId,
			instantiationService.createInstance(
				ChatUrlFetchingConfirmationContribution,
				params => (params as IFetchWebPageToolParams).urls
			)
		));

		// Register external path confirmation contribution for read_file and list_dir
		// They share the same allowlist so approving a folder for reading files also allows listing that directory
		const externalPathConfirmation = new ChatExternalPathConfirmationContribution(
			(ref) => {
				const params = ref.parameters as { filePath?: string; path?: string };
				// read_file uses filePath (it's a file), list_dir uses path (it's a directory)
				if (params?.filePath) {
					return { path: params.filePath, isDirectory: false };
				}
				if (params?.path) {
					return { path: params.path, isDirectory: true };
				}
				return undefined;
			},
			labelService,
			async (pathUri: URI) => {
				// Walk up from the path looking for a .git folder to find the repository root
				let dir = dirname(pathUri);
				for (let i = 0; i < 100; i++) {
					try {
						if (await fileService.exists(URI.joinPath(dir, '.git'))) {
							return dir;
						}
					} catch {
						// ignore permission errors etc.
					}
					const parent = dirname(dir);
					if (extUriBiasedIgnorePathCase.isEqual(parent, dir)) {
						return undefined;
					}
					dir = parent;
				}
				return undefined;
			},
			storageService,
			async () => {
				const result = await fileDialogService.showOpenDialog({
					canSelectFolders: true,
					canSelectFiles: false,
					canSelectMany: false,
				});
				return result?.[0];
			}
		);
		this._register(externalPathConfirmation);

		this._register(confirmationService.registerConfirmationContribution(
			'copilot_readFile',
			externalPathConfirmation
		));

		this._register(confirmationService.registerConfirmationContribution(
			'copilot_listDirectory',
			externalPathConfirmation
		));
	}
}
