import * as childProcess from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
import * as marked from 'marked';
import * as vscode from 'vscode';
import { MergeRequestModel } from '../coding/mergeRequestModel';
import {
	_getMergeRequestInfo,
	describeMergeRequest,
	describeMergeRequestLog,
	describeProjectByName,
	describeProjectDepotInfoList,
	getCurrentUserInfo,
	initCodingApi,
} from '../codingApi';
import Logger from '../common/logger';
import { getWorkspaceRootPath } from '../common/utils';
import { getNonce, IRequestMessage, WebviewViewBase } from '../common/webview';

type DepotInfo = { Name: string; Id: number; SshUrl: string; HttpsUrl: string };

export const createMergeRequestModel = async ({
	mergeId,
	currentDepot,
}: {
	mergeId: number;
	currentDepot: DepotInfo;
}) => {
	const [
		{ data: userData },
		mergeRequestDetail,
		{
			data: { merge_request },
		},
		mergeRequestLogs,
	] = await Promise.all([
		getCurrentUserInfo(),
		describeMergeRequest({ mergeId, depotId: currentDepot.Id }),
		_getMergeRequestInfo({ mergeId }),
		describeMergeRequestLog({ mergeId, depotId: currentDepot.Id }),
	]);

	const {
		MergeRequestInfo: { Title, Describe, Status, SourceBranch, TargetBranch, UpdatedAt, CreatedAt },
	} = mergeRequestDetail;

	// 从操作记录中找到 mr 创建者
	const authorDetail = mergeRequestLogs.Logs.find(item => item.Action === 'create');

	const mrModel = new MergeRequestModel(
		{ id: currentDepot.Id, name: currentDepot.Name },
		{
			mergeId,
			title: Title,
			description: Describe,
			status: Status,
			base: SourceBranch,
			head: TargetBranch,
			updatedAt: UpdatedAt,
			createAt: CreatedAt,
			sshUrl: currentDepot.SshUrl,
			httpsUrl: currentDepot.HttpsUrl,
			author: { id: authorDetail?.Id, name: authorDetail?.Name },
			conflicts: merge_request.conflicts,
		},
		{ id: userData.id, name: userData.name },
	);

	return mrModel;
};

export class MergeRequestViewProvider extends WebviewViewBase implements vscode.WebviewViewProvider {
	public readonly viewType = 'coding.view.active-merge-request';
	// private _existingReviewers: ReviewState[] = [];
	// private _prChangeListener: vscode.Disposable | undefined;
	// private _view: vscode.WebviewView;

	constructor(extensionUri: vscode.Uri, private _mergeRequestModel: MergeRequestModel) {
		super(extensionUri);
	}

	public resolveWebviewView(
		webviewView: vscode.WebviewView,
		_context: vscode.WebviewViewResolveContext,
		_token: vscode.CancellationToken,
	) {
		super.resolveWebviewView(webviewView, _context, _token);
		webviewView.webview.html = this._getHtmlForWebview();

		this.updateMergeRequest(this._mergeRequestModel);
	}

	protected async _onDidReceiveMessage(message: IRequestMessage<any>) {
		Logger.appendLine(`ReceiveMessage: ${message}`);
		const result = await super._onDidReceiveMessage(message);
		if (result !== this.MESSAGE_UNHANDLED) {
			return;
		}

		switch (message.command) {
			case 'alert':
				vscode.window.showErrorMessage(message.args);
				return;
			case 'mr.close':
				return this.close(message);
			case 'mr.refresh':
				return this.refresh(message);
			// case 'mr.merge':
			// return this.mergePullRequest(message);
			// case 'mr.open-create':
			// 	return this.create();
			case 'mr.deleteBranch':
				return this.deleteBranch(message);
			case 'mr.readyForReview':
				return this.setReadyForReview(message);
			case 'mr.approve':
				return this.approveMergeRequest(message);
			case 'mr.request-changes':
				return this.requestChanges(message);
			case 'mr.submit':
				return this.submitReview(message);
			case 'mr.mergeBranch':
				return this.fetchAndMergeBranch(message);
			case 'mr.checkLocalMergeStatus':
				return this.checkLocalMergeStatus(message);
			case 'mr.getLocalConflictFileList':
				return this.getLocalConflictFileList(message);
			case 'mr.openMergeEditor':
				return this.openMergeEditor(message);
			case 'mr.mergeCommitAndPush':
				return this.mergeCommitAndPush(message);
			// case 'mr.openOnGitHub':
			// 	return openPullRequestOnGitHub(this._item, (this._item as any)._telemetry);
			case 'mr.exitReviewMode':
			case 'mr.checkout-default-branch':
				return this.checkoutDefaultBranch(message);
		}
	}

	private async checkoutDefaultBranch(message: IRequestMessage<string>): Promise<void> {
		try {
			await vscode.commands.executeCommand('coding.mr.checkout-default-branch');
			vscode.commands.executeCommand('setContext', 'coding:inReviewMode', false);
			this._replyMessage(message, true);
		} catch (error) {
			this._replyMessage(message, false);
		}
	}

	private async fetchAndMergeBranch(message: IRequestMessage<{ base: string; head: string }>): Promise<void> {
		const { base, head } = message.args;

		childProcess.exec(`git fetch origin ${base}`, { cwd: getWorkspaceRootPath() }, err => {
			if (err) {
				console.log('git fetch error: ', err);
			}

			childProcess.exec(
				// cs 的工作空间初始化，git clone 的 depth 默认为 1，有可能会 merge 报错，加上 `allow-unrelated-histories` 参数强制 merge
				`git merge origin/${head || 'master'} --allow-unrelated-histories`,
				{ cwd: getWorkspaceRootPath() },
				(err, stdout) => {
					if (err) {
						console.error('git merge error', err);
					}

					console.log('git merge success: ', stdout);
				},
			); // @TODO set targeBranch
		});
	}

	private checkLocalMergeStatus(message) {
		// TODO 判断当前分支和目标分支
		const MEAGE_HEAD_FILE = '.git/MERGE_HEAD';
		const filePath = path.join(getWorkspaceRootPath(), MEAGE_HEAD_FILE);
		const hasMergeFile = fs.existsSync(filePath);

		this._replyMessage(message, hasMergeFile);
	}

	private getLocalConflictFileList(message: IRequestMessage<any>): void {
		// 返回当前 mr 冲突的文件列表
		childProcess.exec(
			`git --no-pager diff --name-only --diff-filter=U`,
			{ cwd: getWorkspaceRootPath() },
			(err, stdout) => {
				if (err) {
					console.error(err);
				}

				const fileList = stdout.split('\n').filter(item => item.length);

				console.log('conflict Count: ', stdout.split('\n'));
				this._replyMessage(message, fileList);
			},
		);
	}

	private mergeCommitAndPush(message: IRequestMessage<string>): void {
		// TODO 精确添加冲突文件，精确描述分支
		childProcess.exec(
			`git add . && git commit -m "resolve git merge conflict"`,
			{ cwd: getWorkspaceRootPath() },
			err => {
				if (err) {
					console.error(err);
					return;
				}

				// TODO 添加分支信息
				childProcess.exec(`git push origin`, { cwd: getWorkspaceRootPath() }, err => {
					if (err) {
						console.error(err);
					}

					// TODO git push
					this._replyMessage(message, true);
				});
			},
		);
	}

	private async openMergeEditor(message: IRequestMessage<{ file: string }>) {
		const workpacePath = getWorkspaceRootPath();
		const fileUri = vscode.Uri.parse(`${workpacePath}/${message.args.file}`);
		vscode.commands.executeCommand('git.openMergeEditor', fileUri);
	}

	public async refresh(message: IRequestMessage<any>): Promise<void> {
		await this.updateMergeRequest(this._mergeRequestModel);
		this._replyMessage(message, true);
	}

	public async updateMergeRequest(mergeRequestModel: MergeRequestModel): Promise<void> {
		this._mergeRequestModel = mergeRequestModel;

		if (!this._view) {
			return;
		}

		const { mergeId, depot, httpsUrl, sshUrl } = mergeRequestModel;

		const mrRes = await createMergeRequestModel({
			mergeId,
			currentDepot: { Name: depot.name, Id: depot.id, SshUrl: sshUrl, HttpsUrl: httpsUrl },
		});

		const { title, description, base, head, author, status, currentUser, createAt, updatedAt, conflicts } = mrRes;

		this._mergeRequestModel = mrRes;

		this._view.title = `#${mergeId} ${title}`;
		const isAuthor = author.id === currentUser.id;

		await this._postMessage({
			command: 'mr.initialize',
			state: {
				mergeId: mergeId,
				url: httpsUrl,
				title: title,
				description: marked.parse(description),
				createdAt: new Date(createAt),
				updateAt: new Date(updatedAt),
				base,
				head,
				// commitsCount: Commits.length, // TODO commit 信息
				canEdit: isAuthor,
				conflicts,
				hasWritePermission: true, // @FIXME 需要查询权限判断
				status,
				// mergeable: PullRequestMergeability; // TODO 判断是否可以合并
				// reviewers: ReviewState[]; // 暂时用不上
				isAuthor,
				currentUser,
				author,
			},
		});
	}

	private close = async (message: IRequestMessage<string>) => {
		const data = await this._mergeRequestModel.close();

		this._replyMessage(message, data);
	};

	// TODO 创建评论功能
	// private create() {
	// 	// this._reviewManager.createPullRequest();
	// }

	private updateReviewers(/* review?: CommonReviewEvent */): void {}

	private async approveMergeRequest(message: IRequestMessage<{ comment: string }>): Promise<void> {
		const commentMessage = message.args?.comment || `approve #${this._mergeRequestModel.mergeId}`;
		const data = await this._mergeRequestModel.approve(commentMessage);

		this._replyMessage(message, data);
	}

	private requestChanges(message: IRequestMessage<string>): void {}

	private submitReview(message: IRequestMessage<string>): void {}

	private async deleteBranch(message: IRequestMessage<any>) {}

	private setReadyForReview(message: IRequestMessage<Record<string, unknown>>): void {}

	private _getHtmlForWebview() {
		const nonce = getNonce();

		const uri = vscode.Uri.joinPath(this._extensionUri, 'dist', 'webview-open-mr-view.js');

		return `<!DOCTYPE html>
			<html lang="en">
				<head>
					<meta charset="UTF-8">
					<meta http-equiv="Content-Security-Policy" content="default-src 'none'; img-src vscode-resource: https:; script-src 'nonce-${nonce}'; style-src vscode-resource: 'unsafe-inline' http: https: data:;">
					<meta name="viewport" content="width=device-width, initial-scale=1.0">

					<title>Active Pull Request</title>
				</head>
				<body>
					<div id="app">Loading page...</div>
					<script nonce="${nonce}" src="${this._webview?.asWebviewUri(uri).toString()}"></script>
				</body>
			</html>`;
	}
}
