import * as vscode from 'vscode';
import { _getMergeRequestList, mergeRequestFileDiff } from '../codingApi';
import { CODING_FILE_SCHEME, GitChangeType, Schemes } from '../common';
import { getCurrentDepot } from '../common/context';
import { TreeNode } from './nodes/treeNode';

export class MergeRequestListProvider implements vscode.TreeDataProvider<vscode.TreeItem> {

	private _onDidChangeTreeData = new vscode.EventEmitter<TreeNode | void>();
	readonly onDidChangeTreeData = this._onDidChangeTreeData.event;

	children: TreeNode[];

	constructor() { }

	getTreeItem(element: vscode.TreeItem): vscode.TreeItem | Thenable<vscode.TreeItem> {
		return element;
	}

	async getChildren(element?: TreeNode | undefined): Promise<TreeNode[] | undefined | null> {
		if (element) return element.getChildren();

		if (this.children?.length) return this.children;

		const res = await _getMergeRequestList();
		const mrList = res.data.list;
		const currentDepot = getCurrentDepot();

		if (!currentDepot || !mrList) return null;

		this.children = mrList.map(
			item => new DiffListNode(item.title, item.iid, Number(currentDepot.Id), item.srcBranch, item.author.avatar),
		);

		return this.children;
	}

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

export class DiffListNode extends TreeNode implements vscode.TreeItem {
	public collapsibleState: vscode.TreeItemCollapsibleState;
	public children: TreeNode[] = [];
	public iconPath: vscode.Uri | vscode.ThemeIcon;
	public contextValue: string;

	constructor(
		/* public parent: TreeNodeParent,  */ title: string,
		public mergeId: number,
		public depotId: number,
		public branch: string,
		avatar: string,
	) {
		super();
		this.collapsibleState = vscode.TreeItemCollapsibleState.Collapsed;
		this.iconPath = vscode.Uri.parse(avatar) ?? new vscode.ThemeIcon('coding');
		this.label = `#${this.mergeId} ${title}`;
		this.id = `mrItem-${mergeId}`;
		this.contextValue = 'mrItem';
		this.branch = branch;
	}

	async getChildren(): Promise<TreeNode[]> {
		const { MergeRequestFileDiff } = await mergeRequestFileDiff({ mergeId: this.mergeId, depotId: this.depotId });
		const { OldSha, NewSha } = MergeRequestFileDiff;
		this.children = MergeRequestFileDiff?.FileDiffs.map(
			item => new FileItemNode(item.Path, '', item.ChangeType, OldSha, NewSha),
		);
		return this.children;
	}

	getTreeItem(): vscode.TreeItem {
		return this;
	}
}

export class FileItemNode extends TreeNode implements vscode.TreeItem {
	public description: string;
	public iconPath: vscode.ThemeIcon;
	public fileChangeResourceUri: vscode.Uri;
	public command: vscode.Command;

	constructor(
		public readonly fileName: string,
		previousFileName: string | undefined,
		public readonly status: GitChangeType,
		baseCommit: string,
		headCommit: string,
	) {
		super();
		const paths = fileName.split('/');
		const _fileName = paths.pop();
		this.fileChangeResourceUri = vscode.Uri.file(fileName).with({
			scheme: CODING_FILE_SCHEME,
			query: JSON.stringify({ status, fileName }),
		});

		this.label = _fileName;
		this.description = paths.join('/');
		this.iconPath = vscode.ThemeIcon.File;

		const queryParams = { fileName, baseCommit, headCommit, status };

		let parentURI = vscode.Uri.file(fileName).with({
			scheme: CODING_FILE_SCHEME,
			query: JSON.stringify({ status, fileName, commit: baseCommit }),
		});

		let headURI = vscode.Uri.file(fileName).with({
			scheme: CODING_FILE_SCHEME,
			query: JSON.stringify({ status, fileName, commit: headCommit }),
		});

		switch (status) {
			case GitChangeType.ADD:
				parentURI = vscode.Uri.file(fileName).with({
					scheme: Schemes.CodingMr,
					query: JSON.stringify({ ...queryParams, commit: baseCommit, isBase: false, isEmpty: true }),
				});
				break;

			case GitChangeType.RENAME:
				// FIXME: RENAME 类型 previousFileName 有问题
				parentURI = vscode.Uri.file(previousFileName!).with({
					scheme: Schemes.CodingMr,
					query: JSON.stringify({ ...queryParams, commit: baseCommit, isBase: false, isEmpty: true }),
				});
				break;

			case GitChangeType.DELETE:
				headURI = vscode.Uri.file(fileName).with({
					scheme: Schemes.CodingMr,
					query: JSON.stringify({
						...queryParams,
						fileName,
						commit: headCommit,
						isBase: true,
						isEmpty: true,
					}),
				});
				break;
		}

		this.command = {
			title: 'Open Diff',
			command: 'coding.showDiff',
			arguments: [parentURI, headURI, `${fileName} (Merge Request Preview)`],
		};
	}

	get resourceUri(): vscode.Uri {
		return vscode.Uri.file(this.fileName).with({ query: this.fileChangeResourceUri.query });
	}

	getTreeItem() {
		return this;
	}
}
