<script lang="ts">
	export let application;
	export let appId;
	import { page, session } from '$app/stores';
	import { onMount } from 'svelte';
	import { errorNotification } from '$lib/form';
	import { dev } from '$app/env';
	import cuid from 'cuid';
	import { goto } from '$app/navigation';
	import { del, get, post, put } from '$lib/api';
	import { gitTokens } from '$lib/store';
	import { t } from '$lib/translations';

	const { id } = $page.params;
	const from = $page.url.searchParams.get('from');

	const updateDeployKeyIdUrl = `/applications/${id}/configuration/deploykey.json`;

	let loading = {
		base: true,
		projects: false,
		branches: false,
		save: false
	};

	let htmlUrl = application.gitSource.htmlUrl;
	let apiUrl = application.gitSource.apiUrl;

	let username = null;
	let groups = [];
	let projects = [];
	let branches = [];
	let showSave = false;
	let autodeploy = application.settings.autodeploy || true;

	let selected = {
		group: undefined,
		project: undefined,
		branch: undefined
	};
	onMount(async () => {
		if (!$gitTokens.gitlabToken) {
			getGitlabToken();
		} else {
			loading.base = true;
			try {
				const user = await get(`${apiUrl}/v4/user`, {
					Authorization: `Bearer ${$gitTokens.gitlabToken}`
				});
				username = user.username;
			} catch (error) {
				return getGitlabToken();
			}
			try {
				groups = await get(`${apiUrl}/v4/groups?per_page=5000`, {
					Authorization: `Bearer ${$gitTokens.gitlabToken}`
				});
			} catch (error) {
				errorNotification(error);
				throw new Error(error);
			} finally {
				loading.base = false;
			}
		}
	});

	function getGitlabToken() {
		const left = screen.width / 2 - 1020 / 2;
		const top = screen.height / 2 - 618 / 2;
		const newWindow = open(
			`${htmlUrl}/oauth/authorize?client_id=${application.gitSource.gitlabApp.appId}&redirect_uri=${window.location.origin}/webhooks/gitlab&response_type=code&scope=api+email+read_repository&state=${$page.params.id}`,
			'GitLab',
			'resizable=1, scrollbars=1, fullscreen=0, height=618, width=1020,top=' +
				top +
				', left=' +
				left +
				', toolbar=0, menubar=0, status=0'
		);
		const timer = setInterval(() => {
			if (newWindow?.closed) {
				clearInterval(timer);
				window.location.reload();
			}
		}, 100);
	}

	async function loadProjects() {
		loading.projects = true;
		if (username === selected.group.name) {
			try {
				projects = await get(
					`${apiUrl}/v4/users/${selected.group.name}/projects?min_access_level=40&page=1&per_page=25&archived=false`,
					{
						Authorization: `Bearer ${$gitTokens.gitlabToken}`
					}
				);
			} catch (error) {
				errorNotification(error);
				throw new Error(error);
			} finally {
				loading.projects = false;
			}
		} else {
			try {
				projects = await get(
					`${apiUrl}/v4/groups/${selected.group.id}/projects?page=1&per_page=25&archived=false`,
					{
						Authorization: `Bearer ${$gitTokens.gitlabToken}`
					}
				);
			} catch (error) {
				errorNotification(error);
				throw new Error(error);
			} finally {
				loading.projects = false;
			}
		}
	}

	async function loadBranches() {
		loading.branches = true;
		try {
			branches = await get(
				`${apiUrl}/v4/projects/${selected.project.id}/repository/branches?per_page=100&page=1`,
				{
					Authorization: `Bearer ${$gitTokens.gitlabToken}`
				}
			);
		} catch (error) {
			errorNotification(error);
			throw new Error(error);
		} finally {
			loading.branches = false;
		}
	}

	async function isBranchAlreadyUsed() {
		try {
			const data = await get(
				`/applications/${id}/configuration/repository.json?repository=${selected.project.path_with_namespace}&branch=${selected.branch.name}`
			);
			if (data.used) {
				const sure = confirm($t('application.configuration.branch_already_in_use'));
				if (sure) {
					autodeploy = false;
					showSave = true;
					return true;
				}
				showSave = false;
				return true;
			}
			showSave = true;
		} catch ({ error }) {
			return errorNotification(error);
		}
	}
	async function checkSSHKey(sshkeyUrl) {
		try {
			return await post(sshkeyUrl, {});
		} catch (error) {
			errorNotification(error);
			throw new Error(error);
		}
	}
	async function setWebhook(url, webhookToken) {
		const host = dev
			? 'https://webhook.site/0e5beb2c-4e9b-40e2-a89e-32295e570c21'
			: `${window.location.origin}/webhooks/gitlab/events`;
		try {
			await post(
				url,
				{
					id: selected.project.id,
					url: host,
					token: webhookToken,
					push_events: true,
					enable_ssl_verification: true,
					merge_requests_events: true
				},
				{
					Authorization: `Bearer ${$gitTokens.gitlabToken}`
				}
			);
		} catch (error) {
			errorNotification(error);
			throw error;
		}
	}
	async function save() {
		loading.save = true;
		let privateSshKey = application.gitSource.gitlabApp.privateSshKey;
		let publicSshKey = application.gitSource.gitlabApp.publicSshKey;

		const deployKeyUrl = `${apiUrl}/v4/projects/${selected.project.id}/deploy_keys`;
		const sshkeyUrl = `/applications/${id}/configuration/sshkey.json`;
		const webhookUrl = `${apiUrl}/v4/projects/${selected.project.id}/hooks`;
		const webhookToken = cuid();

		try {
			if (!privateSshKey || !publicSshKey) {
				const { publicKey } = await checkSSHKey(sshkeyUrl);
				publicSshKey = publicKey;
			}
			const deployKeys = await get(deployKeyUrl, {
				Authorization: `Bearer ${$gitTokens.gitlabToken}`
			});
			const deployKeyFound = deployKeys.filter((dk) => dk.title === `${appId}-coolify-deploy-key`);
			if (deployKeyFound.length > 0) {
				for (const deployKey of deployKeyFound) {
					await del(
						`${deployKeyUrl}/${deployKey.id}`,
						{},
						{
							Authorization: `Bearer ${$gitTokens.gitlabToken}`
						}
					);
				}
			}
			const { id } = await post(
				deployKeyUrl,
				{
					title: `${appId}-coolify-deploy-key`,
					key: publicSshKey,
					can_push: false
				},
				{
					Authorization: `Bearer ${$gitTokens.gitlabToken}`
				}
			);
			await post(updateDeployKeyIdUrl, { deployKeyId: id });
		} catch (error) {
			console.log(error);
			throw new Error(error);
		}

		try {
			await setWebhook(webhookUrl, webhookToken);
		} catch (err) {
			console.log(err);
			if (!dev) throw new Error(err);
		}

		const url = `/applications/${id}/configuration/repository.json`;
		try {
			const repository = selected.project.path_with_namespace;
			await post(url, {
				repository,
				branch: selected.branch.name,
				projectId: selected.project.id,
				autodeploy,
				webhookToken
			});
			return await goto(from || `/applications/${id}/configuration/buildpack`);
		} catch ({ error }) {
			return errorNotification(error);
		}
	}
	async function handleSubmit() {
		try {
			await post(`/applications/{id}/configuration/repository.json`, { ...selected });
			return await goto(from || `/applications/${id}/configuration/destination`);
		} catch ({ error }) {
			return errorNotification(error);
		}
	}
</script>

<form on:submit={handleSubmit}>
	<div class="flex flex-col space-y-2 px-4 xl:flex-row xl:space-y-0 xl:space-x-2 ">
		{#if loading.base}
			<select name="group" disabled class="w-96">
				<option selected value="">{$t('application.configuration.loading_groups')}</option>
			</select>
		{:else}
			<select name="group" class="w-96" bind:value={selected.group} on:change={loadProjects}>
				<option value="" disabled selected>{$t('application.configuration.select_a_group')}</option>
				{#each groups as group}
					<option value={group}>{group.full_name}</option>
				{/each}
			</select>
		{/if}
		{#if loading.projects}
			<select name="project" disabled class="w-96">
				<option selected value="">{$t('application.configuration.loading_projects')}</option>
			</select>
		{:else if !loading.projects && projects.length > 0}
			<select
				name="project"
				class="w-96"
				bind:value={selected.project}
				on:change={loadBranches}
				disabled={!selected.group}
			>
				<option value="" disabled selected
					>{$t('application.configuration.select_a_project')}</option
				>
				{#each projects as project}
					<option value={project}>{project.name}</option>
				{/each}
			</select>
		{:else}
			<select name="project" disabled class="w-96">
				<option disabled selected value=""
					>{$t('application.configuration.no_projects_found')}</option
				>
			</select>
		{/if}

		{#if loading.branches}
			<select name="branch" disabled class="w-96">
				<option selected value="">{$t('application.configuration.loading_branches')}</option>
			</select>
		{:else if !loading.branches && branches.length > 0}
			<select
				name="branch"
				class="w-96"
				bind:value={selected.branch}
				on:change={isBranchAlreadyUsed}
				disabled={!selected.project}
			>
				<option value="" disabled selected>{$t('application.configuration.select_a_branch')}</option
				>
				{#each branches as branch}
					<option value={branch}>{branch.name}</option>
				{/each}
			</select>
		{:else}
			<select name="project" disabled class="w-96">
				<option disabled selected value=""
					>{$t('application.configuration.no_branches_found')}</option
				>
			</select>
		{/if}
	</div>
	<div class="flex flex-col items-center justify-center space-y-4 pt-5">
		<button
			on:click|preventDefault={save}
			class="w-40"
			type="submit"
			disabled={!showSave || loading.save}
			class:bg-orange-600={showSave && !loading.save}
			class:hover:bg-orange-500={showSave && !loading.save}
			>{loading.save ? $t('forms.saving') : $t('forms.save')}</button
		>
	</div>
</form>
