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

import * as path from 'path';
import * as fs from 'fs';
import URI from 'vscode-uri';

import { TextDocument, CompletionList, CompletionItemKind, CompletionItem, TextEdit, Range, Position } from 'vscode-languageserver-types';
import { WorkspaceFolder } from 'vscode-languageserver';
import { ICompletionParticipant, URILiteralCompletionContext } from 'vscode-css-languageservice';

import { startsWith } from './utils/strings';

export function getPathCompletionParticipant(
	document: TextDocument,
	workspaceFolders: WorkspaceFolder[] | undefined,
	result: CompletionList
): ICompletionParticipant {
	return {
		onURILiteralValue: (context: URILiteralCompletionContext) => {
			if (!workspaceFolders || workspaceFolders.length === 0) {
				return;
			}
			const workspaceRoot = resolveWorkspaceRoot(document, workspaceFolders);

			// Handle quoted values
			let uriValue = context.uriValue;
			let range = context.range;
			if (startsWith(uriValue, `'`) || startsWith(uriValue, `"`)) {
				uriValue = uriValue.slice(1, -1);
				range = getRangeWithoutQuotes(range);
			}

			const suggestions = providePathSuggestions(uriValue, range, URI.parse(document.uri).fsPath, workspaceRoot);
			result.items = [...suggestions, ...result.items];
		}
	};
}

export function providePathSuggestions(value: string, range: Range, activeDocFsPath: string, root?: string): CompletionItem[] {
	if (startsWith(value, '/') && !root) {
		return [];
	}

	let replaceRange: Range;
	const lastIndexOfSlash = value.lastIndexOf('/');
	if (lastIndexOfSlash === -1) {
		replaceRange = getFullReplaceRange(range);
	} else {
		const valueAfterLastSlash = value.slice(lastIndexOfSlash + 1);
		replaceRange = getReplaceRange(range, valueAfterLastSlash);
	}

	const valueBeforeLastSlash = value.slice(0, lastIndexOfSlash + 1);

	const parentDir = startsWith(value, '/')
		? path.resolve(root, '.' + valueBeforeLastSlash)
		: path.resolve(activeDocFsPath, '..', valueBeforeLastSlash);

	try {
		return fs.readdirSync(parentDir).map(f => {
			if (isDir(path.resolve(parentDir, f))) {
				return {
					label: f + '/',
					kind: CompletionItemKind.Folder,
					textEdit: TextEdit.replace(replaceRange, f + '/'),
					command: {
						title: 'Suggest',
						command: 'editor.action.triggerSuggest'
					}
				};
			} else {
				return {
					label: f,
					kind: CompletionItemKind.File,
					textEdit: TextEdit.replace(replaceRange, f)
				};
			}
		});
	} catch (e) {
		return [];
	}
}

const isDir = (p: string) => {
	try {
		return fs.statSync(p).isDirectory();
	} catch (e) {
		return false;
	}
};

function resolveWorkspaceRoot(activeDoc: TextDocument, workspaceFolders: WorkspaceFolder[]): string | undefined {
	for (let i = 0; i < workspaceFolders.length; i++) {
		if (startsWith(activeDoc.uri, workspaceFolders[i].uri)) {
			return path.resolve(URI.parse(workspaceFolders[i].uri).fsPath);
		}
	}
}

function getFullReplaceRange(valueRange: Range) {
	const start = Position.create(valueRange.end.line, valueRange.start.character);
	const end = Position.create(valueRange.end.line, valueRange.end.character);
	return Range.create(start, end);
}
function getReplaceRange(valueRange: Range, valueAfterLastSlash: string) {
	const start = Position.create(valueRange.end.line, valueRange.end.character - valueAfterLastSlash.length);
	const end = Position.create(valueRange.end.line, valueRange.end.character);
	return Range.create(start, end);
}
function getRangeWithoutQuotes(range: Range) {
	const start = Position.create(range.start.line, range.start.character + 1);
	const end = Position.create(range.end.line, range.end.character - 1);
	return Range.create(start, end);
}
