import type { TextDocumentShowOptions, TextEditor, Uri } from 'vscode';
import { Range, window } from 'vscode';
import { Logger } from '@gitlens/utils/logger.js';
import type { FileAnnotationType } from '../config.js';
import type { Container } from '../container.js';
import { GitUri, isGitUri } from '../git/gitUri.js';
import { showGenericErrorMessage } from '../messages.js';
import { command } from '../system/-webview/command.js';
import { getOrOpenTextEditor } from '../system/-webview/vscode/editors.js';
import { ActiveEditorCommand } from './commandBase.js';
import { getCommandUri } from './commandBase.utils.js';

export interface OpenWorkingFileCommandArgs {
	uri?: Uri;
	line?: number;
	showOptions?: TextDocumentShowOptions;
	annotationType?: FileAnnotationType;
}

@command()
export class OpenWorkingFileCommand extends ActiveEditorCommand {
	constructor(private readonly container: Container) {
		super([
			'gitlens.openWorkingFile',
			'gitlens.openWorkingFile:command',
			'gitlens.openWorkingFile:editor/context',
			'gitlens.openWorkingFile:editor/title',
		]);
	}

	async execute(editor: TextEditor, uri?: Uri, args?: OpenWorkingFileCommandArgs): Promise<void> {
		args = { ...args };
		args.line ??= editor?.selection.active.line;

		try {
			if (args.uri == null) {
				uri = getCommandUri(uri, editor);
				if (uri == null) return;
			} else {
				uri = args.uri;
			}

			args.uri = await GitUri.fromUri(uri);
			if (isGitUri(args.uri) && args.uri.sha) {
				const workingUri = await this.container.git
					.getRepositoryService(args.uri.repoPath!)
					.getWorkingUri(args.uri);
				if (workingUri === undefined) {
					void window.showWarningMessage(
						'Unable to open working file. File could not be found in the working tree',
					);

					return;
				}

				args.uri = new GitUri(workingUri, args.uri.repoPath);
			}

			if (args.line !== undefined && args.line !== 0) {
				if (args.showOptions === undefined) {
					args.showOptions = {};
				}
				args.showOptions.selection = new Range(args.line, 0, args.line, 0);
			}

			const e = await getOrOpenTextEditor(args.uri, { ...args.showOptions, throwOnError: true });
			if (args.annotationType === undefined) return;

			void (await this.container.fileAnnotations.show(e, args.annotationType, {
				selection: { line: args.line },
			}));
		} catch (ex) {
			Logger.error(ex, 'OpenWorkingFileCommand');
			void showGenericErrorMessage('Unable to open working file');
		}
	}
}
