import { URL } from 'url';
import vscode, { Uri } from 'vscode';
import { MergeRequestModel } from './coding/mergeRequestModel';
import {
	_getMergeRequestList,
	DescribeDepotDefaultBranch,
	describeProjectByName,
	describeProjectDepotInfoList,
	initCodingApi,
} from './codingApi';
import { getCommonExtension } from './common/commonExtention';
import { bindExtensionContext } from './common/context';
import Logger from './common/logger';
import { getSession, getSessions } from './common/login';
import { BuiltinGitProvider } from './gitProviders/builtinGit';
import { CodingContentProvider } from './gitProviders/codingContentProvider';
import { CodingMergeRequestFileSystemProvider } from './gitProviders/gitContentProvider';
import { replyNote, showDiffComment } from './reviewCommentController';
import { FileTypeDecorationProvider } from './views/fileTypeDecorationProvider';
import { MergeRequestsTreeDataProvider } from './views/MergeRequestTreeDataProvider';
import { MergeRequestListProvider } from './views/MergeRequestTreeListProvider';
import { createMergeRequestModel, MergeRequestViewProvider } from './views/MergeRequestViewProvider';

export async function activate(context: vscode.ExtensionContext) {
	bindExtensionContext(context);

	vscode.commands.executeCommand('setContext', 'coding:needToLogin', true);

	let codingDeployHost: string = 'coding.net';
	let codingDepotHost: string = 'e.coding.net';

	try {
		// 通过 Common 插件获取 config 配置
		const extension = getCommonExtension();
		const config = await extension?.getPublicConfig();
		if (typeof config?.privateCodingDeployHost === 'string') {
			codingDeployHost = config?.privateCodingDeployHost;
		}

		if (config?.privateCodingDepotHost) {
			codingDepotHost = config?.privateCodingDepotHost;
		}
	} catch (error) {
		// 在 vscode 环境中可能会因没有依赖报错，可忽略
		Logger.appendLine('>>> getConfig: ', error);
	}

	context.globalState.update('codingDepolyHost', codingDeployHost);
	context.globalState.update('codingDepotHost', codingDepotHost);

	let teamName: string | undefined;
	let project: string | undefined;
	let currentDepot: { Name: string; Id: number; SshUrl: string; HttpsUrl: string } | undefined;
	let mergeId: number | undefined;
	let token: string | undefined;
	let browserUrl: string | undefined;
	let currentBranch: string | undefined;

	try {
		browserUrl = await vscode.commands.executeCommand('cloudstudio.getBrowserUrl');
	} catch (error) {
		// @test 本地测试  merge url: https://cloudstudio-demo.coding.net/p/cloudnative/d/mr/git/merge/2?initial=true
		const localUrl = context.globalState.get<string>('testUrl');

		browserUrl =
			localUrl ??
			'https://leo-mars.cloudstudio.net/tty/gmwyot/?ws_f_repo=true&project=qci-test&mr_id=8&repo=Axios&branch=test-4-2';
	}

	const builtinGit = await BuiltinGitProvider.createProvider();
	let repository = builtinGit?.repositories[0];

	builtinGit?.onDidOpenRepository(() => {
		console.log('builtinGit: ', builtinGit?.repositories);
	});

	builtinGit?.onDidChangeState(state => {
		if (state === 'initialized') {
			initParamsfromQueryOrLocal();
		}
		console.log('change state: ', state);
	});

	// 在 CS 环境里，可能不会执行 builtinGit 的 event，先尝试执行一次初始化
	setTimeout(() => initParamsfromQueryOrLocal(), 10);

	const initParamsfromQueryOrLocal = async () => {
		try {
			let repo: string | undefined;

			// @test 暂时隐藏
			// try {
			// 	const urlObject = new URL(browserUrl ?? '');
			// 	teamName = urlObject.host.split('.').shift();
			// 	const { project: p, repo: r, branch, mr_id } = Object.fromEntries(urlObject.searchParams.entries());
			// 	currentBranch = branch;
			// 	project = p;
			// 	repo = r;
			// 	mergeId = Number(mr_id);
			// } catch (error) {}

			if (!(teamName && project && repo)) {
				// 如果没有对应的浏览器 URL 参数，则从本地仓库 remote 解析
				if (!repository) return;

				Logger.appendLine(`repository remotes: ${JSON.stringify(repository.state.remotes)}`);

				const remotes = repository.state.remotes;
				const originRemote = remotes.find(repo => repo.fetchUrl?.includes(codingDepotHost));
				let fetchUrl = originRemote?.fetchUrl;

				if (fetchUrl?.startsWith('git@')) {
					fetchUrl = fetchUrl.replace(/:/, '/').replace(/git@/, 'https://');
				}
				Logger.appendLine(`fetchUrl: ${fetchUrl}`);

				if (!fetchUrl) return;

				const urlObject = new URL(fetchUrl);
				const [_, t, p, r] = urlObject.pathname.split('/');
				teamName = t;
				project = p;
				repo = r.replace(/\.git$/, '');

				const head = repository.state.HEAD;
				currentBranch = head?.name;
			}

			Logger.appendLine(`teamName: ${teamName}, project: ${project}, repo: ${repo}`);

			if (!teamName || !project || !repo) return;

			let session = await getSession();

			if (!session) {
				session = (await getSessions(false) || []).filter(item => item.team === teamName)[0];
				Logger.appendLine(`session: ${JSON.stringify(session)}`);
			}
			if (!session) return;
			token = session?.accessToken;

			// 必须初始化 API，才可以调用
			initCodingApi({ teamName, token, project, depot: repo });

			if (token) {
				vscode.commands.executeCommand('setContext', 'coding:needToLogin', false);
				Logger.appendLine(`coding:needToLogin false`);
			}

			const {
				Project: { Id: projectId },
			} = await describeProjectByName({ projectName: project });

			const {
				DepotData: { Depots },
			} = await describeProjectDepotInfoList({ projectId });

			const foundDepot = Depots.find(
				item => item.Name.toLowerCase() === repo?.toLowerCase() && item.VcsType === 'git',
			);

			if (foundDepot) {
				currentDepot = foundDepot;
				context.globalState.update('currentDepot', foundDepot);
				context.globalState.update('teamName', teamName);
			}

			try {
				if (currentBranch && repository) {
					await repository.fetch({ ref: currentBranch });
					await repository.checkout(currentBranch);
				}
			} catch (e) {
				console.log('repository fetch err', e);
			}

			Logger.appendLine(`currentDepot:${JSON.stringify(currentDepot)}`);
			if (!currentDepot) return;

			vscode.commands.executeCommand('setContext', 'coding:isCodingRepo', true);

			repository?.state.onDidChange(() => {
				initReviewMode();
			});

		} catch (error) {
			console.error(error);
			Logger.appendLine(`init error: ${error}`);
		}
	};

	context.subscriptions.push(
		vscode.workspace.registerFileSystemProvider(
			CodingMergeRequestFileSystemProvider.scheme,
			new CodingMergeRequestFileSystemProvider(builtinGit!),
			{ isReadonly: true },
		),
	);

	context.subscriptions.push(
		vscode.workspace.registerFileSystemProvider(
			CodingContentProvider.scheme,
			new CodingContentProvider(builtinGit!),
			{ isReadonly: true },
		),
	);

	let mrModel: undefined | MergeRequestModel;
	let webviewViewProvider;

	const initReviewMode = async () => {
		const currentBranch = repository?.state.HEAD?.name;

		if (!currentBranch) {
			vscode.commands.executeCommand('setContext', 'coding:inReviewMode', false);
		}

		if (mrModel && mrModel.base === currentBranch) {
			return;
		}

		const { data } = await _getMergeRequestList();

		const currentMr = data?.list.find(mr => mr.srcBranch === currentBranch);
		const mergeId = currentMr?.iid;

		if (!(mergeId && currentDepot)) {
			vscode.commands.executeCommand('setContext', 'coding:inReviewMode', false);
			return;
		}

		mrModel = await createMergeRequestModel({ mergeId, currentDepot });
		// mr diff 列表
		context.subscriptions.push(new MergeRequestsTreeDataProvider(mrModel));

		if (webviewViewProvider) {
			webviewViewProvider.updateMergeRequest(mrModel);
		} else {
			webviewViewProvider = new MergeRequestViewProvider(context.extensionUri, mrModel);

			context.subscriptions.push(
				vscode.window.registerWebviewViewProvider(webviewViewProvider.viewType, webviewViewProvider),
			);
		}

		vscode.commands.executeCommand('setContext', 'coding:inReviewMode', true);

		// focus 到 panel
		vscode.commands.executeCommand(`${webviewViewProvider.viewType}.focus`);
	};

	const mergeRequestListProvider = new MergeRequestListProvider();

	context.subscriptions.push(
		vscode.window.createTreeView(`coding.view.mrList`, {
			treeDataProvider: mergeRequestListProvider,
			showCollapseAll: true,
		}),
	);

	vscode.commands.registerCommand('coding.mr.refresh', function () {
		mergeRequestListProvider.refresh();
	});

	context.subscriptions.push(new FileTypeDecorationProvider());

	vscode.commands.registerCommand(`diff.createComment`, async (reply: vscode.CommentReply) => {
		await replyNote(reply);
	});

	vscode.commands.registerCommand(`diff.replyComment`, async (reply: vscode.CommentReply) => {
		await replyNote(reply);
	});

	vscode.commands.registerCommand('coding.showDiff', async (parentUri: Uri, headUri: Uri, title: string) => {
		await vscode.commands.executeCommand(`vscode.diff`, parentUri, headUri, title, { preserveFocus: true });

		if (!mrModel) return;
		await showDiffComment(parentUri, headUri, mrModel);
	});

	vscode.commands.registerCommand('coding.mr.openMrUrl', async (...args) => {
		if (!mrModel) return;

		const urlObject = new URL(mrModel.httpsUrl);
		const [_, team, project, repo] = urlObject.pathname.split('/');
		const mrUrl = `https://${team}.${codingDeployHost}/p/${project}/d/${repo.replace('.', '/')}/merge/${
			mrModel.mergeId
		}`;

		vscode.env.openExternal(vscode.Uri.parse(mrUrl));
	});

	vscode.commands.registerCommand('coding.mr.openMrCreatePage', async () => {
		if (!currentDepot) return;

		const urlObject = new URL(currentDepot?.HttpsUrl);
		const [_, team, project, repo] = urlObject.pathname.split('/');

		const targetUrl = `https://${team}.${codingDeployHost}/p/${project}/d/${repo.replace('.', '/')}/merges/create`;

		vscode.env.openExternal(vscode.Uri.parse(targetUrl));
	});

	vscode.commands.registerCommand('coding.mr.pick', async (node: Record<string, any>) => {
		try {
			const browserUrl = await vscode.commands.executeCommand<string>('cloudstudio.getBrowserUrl');

			const urlObj = new URL(browserUrl!);
			urlObj.searchParams.set('mr_id', node.mergeId);
			urlObj.searchParams.set('branch', node.branch);
			await repository?.fetch({ ref: node.branch });
			await repository?.checkout(node.branch);
		} catch (error) {
			// @test 本地测试
			const urlObj = new URL(browserUrl!);
			urlObj.searchParams.set('mr_id', node.mergeId);
			urlObj.searchParams.set('branch', node.branch);
			context.globalState.update('testUrl', urlObj.toString());
			await repository?.fetch({ ref: node.branch });
			await repository?.checkout(node.branch);
		}
	});

	vscode.commands.registerCommand('coding.mr.checkout-default-branch', async () => {
		if (teamName && project && currentDepot) {
			const defaultBranch = await DescribeDepotDefaultBranch({
				team: teamName,
				project,
				depot: currentDepot.Name,
			});
			repository?.checkout(defaultBranch.BranchName);
		}
	});

	vscode.commands.registerCommand('coding.welcome.login', async () => {
		const res = await getSessions();
		console.log('res: ', res);

		if (res) {
			await getSession({ timeout: 10000, silent: false });
			await initParamsfromQueryOrLocal();
		}
	});
}
