<script context="module" lang="ts">
	import type { Load } from '@sveltejs/kit';
	export const load: Load = async ({ fetch, params, stuff, url }) => {
		try {
			if (stuff?.application?.id) {
				return {
					props: {
						application: stuff.application,
						settings: stuff.settings
					}
				};
			}
			const response = await get(`/applications/${params.id}`);
			return {
				props: {
					...response
				}
			};
		} catch (error) {
			return {
				status: 500,
				error: new Error(`Could not load ${url}`)
			};
		}
	};
</script>

<script lang="ts">
	export let application: any;
	export let settings: any;

	import yaml from 'js-yaml';
	import { page } from '$app/stores';
	import { onMount } from 'svelte';
	import Select from 'svelte-select';
	import { get, getAPIUrl, post } from '$lib/api';
	import cuid from 'cuid';
	import {
		addToast,
		appSession,
		checkIfDeploymentEnabledApplications,
		setLocation,
		status,
		isDeploymentEnabled,
		features
	} from '$lib/store';
	import { t } from '$lib/translations';
	import { errorNotification, getDomain, notNodeDeployments, staticDeployments } from '$lib/common';
	import Setting from '$lib/components/Setting.svelte';
	import Explainer from '$lib/components/Explainer.svelte';
	import { goto } from '$app/navigation';
	import Beta from '$lib/components/Beta.svelte';

	const { id } = $page.params;

	$: isDisabled =
		!$appSession.isAdmin ||
		$status.application.overallStatus === 'degraded' ||
		$status.application.overallStatus === 'healthy' ||
		$status.application.initialLoading;

	$isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application);
	let statues: any = {};
	let loading = {
		save: false,
		reloadCompose: false
	};
	let fqdnEl: any = null;
	let forceSave = false;
	let isPublicRepository = application.settings?.isPublicRepository;
	let apiUrl = application.gitSource?.apiUrl;
	let branch = application.branch;
	let repository = application.repository;
	let debug = application.settings?.debug;
	let previews = application.settings?.previews;
	let dualCerts = application.settings?.dualCerts;
	let isCustomSSL = application.settings?.isCustomSSL;
	let autodeploy = application.settings?.autodeploy;
	let isBot = application.settings?.isBot;
	let isDBBranching = application.settings?.isDBBranching;
	let htmlUrl = application.gitSource?.htmlUrl;

	let dockerComposeFile = JSON.parse(application.dockerComposeFile) || null;
	let dockerComposeServices: any[] = [];
	let dockerComposeConfiguration = JSON.parse(application.dockerComposeConfiguration) || {};
	let originalDockerComposeFileLocation = application.dockerComposeFileLocation;

	let baseDatabaseBranch: any = application?.connectedDatabase?.hostedDatabaseDBName || null;
	let nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
	let isHttps = application.fqdn && application.fqdn.startsWith('https://');
	let isNonWWWDomainOK = false;
	let isWWWDomainOK = false;

	let wsgis = [
		{
			value: 'None',
			label: 'None'
		},
		{
			value: 'Gunicorn',
			label: 'Gunicorn'
		},
		{
			value: 'Uvicorn',
			label: 'Uvicorn'
		}
	];
	function normalizeDockerServices(services: any[]) {
		const tempdockerComposeServices = [];
		for (const [name, data] of Object.entries(services)) {
			tempdockerComposeServices.push({
				name,
				data
			});
		}
		for (const service of tempdockerComposeServices) {
			if (!dockerComposeConfiguration[service.name]) {
				dockerComposeConfiguration[service.name] = {};
			}
		}
		return tempdockerComposeServices;
	}
	if (dockerComposeFile?.services) {
		dockerComposeServices = normalizeDockerServices(dockerComposeFile.services);
	}

	function containerClass() {
		return 'text-white bg-transparent font-thin px-0 w-full border border-dashed border-coolgray-200';
	}

	onMount(async () => {
		if (window.location.hostname === 'demo.coolify.io' && !application.fqdn) {
			application.fqdn = `http://${cuid()}.demo.coolify.io`;
			await handleSubmit();
		}
		await getBaseBuildImages();
		if (!application.fqdn && fqdnEl) fqdnEl.focus();
	});
	async function getBaseBuildImages() {
		const data = await post(`/applications/images`, {
			buildPack: application.buildPack,
			deploymentType: application.deploymentType
		});
		const baseImageCorrect = data.baseImages.filter(
			(image: any) => image.value === application.baseImage
		);
		if (baseImageCorrect.length === 0) {
			application.baseImage = data.baseImage;
		}
		application.baseImages = data.baseImages;

		const baseBuildImageCorrect = data.baseBuildImages.filter(
			(image: any) => image.value === application.baseBuildImage
		);
		if (baseBuildImageCorrect.length === 0) {
			application.baseBuildImage = data.baseBuildImage;
		}
		application.baseBuildImages = data.baseBuildImages;
		if (application.deploymentType === 'static' && application.port !== '80') {
			application.port = data.port;
		}
		if (application.deploymentType === 'node' && application.port === '80') {
			application.port = data.port;
		}
		if (application.deploymentType === 'static' && !application.publishDirectory) {
			application.publishDirectory = data.publishDirectory;
		}
		if (application.deploymentType === 'node' && application.publishDirectory === 'out') {
			application.publishDirectory = data.publishDirectory;
		}
	}
	async function changeSettings(name: any) {
		if (name === 'debug') {
			debug = !debug;
		}
		if (name === 'previews') {
			previews = !previews;
		}
		if (name === 'dualCerts') {
			dualCerts = !dualCerts;
		}
		if (name === 'autodeploy') {
			autodeploy = !autodeploy;
		}
		if (name === 'isCustomSSL') {
			isCustomSSL = !isCustomSSL;
		}
		if (name === 'isBot') {
			if ($status.application.overallStatus !== 'stopped') return;
			isBot = !isBot;
			application.settings.isBot = isBot;
			application.fqdn = null;
			setLocation(application, settings);
		}
		if (name === 'isDBBranching') {
			isDBBranching = !isDBBranching;
		}
		try {
			await post(`/applications/${id}/settings`, {
				previews,
				debug,
				dualCerts,
				isBot,
				autodeploy,
				isDBBranching,
				isCustomSSL,
				branch: application.branch,
				projectId: application.projectId
			});
			return addToast({
				message: $t('application.settings_saved'),
				type: 'success'
			});
		} catch (error) {
			if (name === 'debug') {
				debug = !debug;
			}
			if (name === 'previews') {
				previews = !previews;
			}
			if (name === 'dualCerts') {
				dualCerts = !dualCerts;
			}
			if (name === 'autodeploy') {
				autodeploy = !autodeploy;
			}
			if (name === 'isBot') {
				isBot = !isBot;
			}
			if (name === 'isDBBranching') {
				isDBBranching = !isDBBranching;
			}
			if (name === 'isCustomSSL') {
				isCustomSSL = !isCustomSSL;
			}
			return errorNotification(error);
		} finally {
			$isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application);
		}
	}
	async function handleSubmit(toast: boolean = true) {
		if (loading.save) return;
		if (toast) loading.save = true;
		try {
			nonWWWDomain = application.fqdn && getDomain(application.fqdn).replace(/^www\./, '');
			if (application.deploymentType) {
				application.deploymentType = application.deploymentType.toLowerCase();
			}
			if (originalDockerComposeFileLocation !== application.dockerComposeFileLocation) {
				await reloadCompose();
			}
			if (!isBot) {
				await post(`/applications/${id}/check`, {
					fqdn: application.fqdn,
					forceSave,
					dualCerts,
					exposePort: application.exposePort
				});
				for (const service of dockerComposeServices) {
					if (dockerComposeConfiguration[service.name].fqdn) {
						await post(`/applications/${id}/check`, {
							fqdn: dockerComposeConfiguration[service.name].fqdn,
							forceSave,
							dualCerts,
							exposePort: application.exposePort
						});
					}
				}
			}
			await post(`/applications/${id}`, {
				...application,
				baseDatabaseBranch,
				dockerComposeConfiguration: JSON.stringify(dockerComposeConfiguration)
			});
			setLocation(application, settings);
			$isDeploymentEnabled = checkIfDeploymentEnabledApplications($appSession.isAdmin, application);

			forceSave = false;

			toast &&
				addToast({
					message: 'Configuration saved.',
					type: 'success'
				});
			if (application.fqdn && application.fqdn.startsWith('https')) {
				isHttps = true;
			} else {
				isHttps = false;
			}
		} catch (error) {
			//@ts-ignore
			if (error?.message.startsWith($t('application.dns_not_set_partial_error'))) {
				forceSave = true;
				if (dualCerts) {
					isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false);
					isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true);
				} else {
					const isWWW = getDomain(application.fqdn).includes('www.');
					if (isWWW) {
						isWWWDomainOK = await isDNSValid(getDomain(`www.${nonWWWDomain}`), true);
					} else {
						isNonWWWDomainOK = await isDNSValid(getDomain(nonWWWDomain), false);
					}
				}
			}
			return errorNotification(error);
		} finally {
			loading.save = false;
		}
	}
	async function selectWSGI(event: any) {
		application.pythonWSGI = event.detail.value;
	}
	async function selectBaseImage(event: any) {
		application.baseImage = event.detail.value;
		await handleSubmit();
	}
	async function selectBaseBuildImage(event: any) {
		application.baseBuildImage = event.detail.value;
		await handleSubmit();
	}
	async function selectDeploymentType(event: any) {
		application.deploymentType = event.detail.value;
		await getBaseBuildImages();
		await handleSubmit();
	}
	async function isDNSValid(domain: any, isWWW: any) {
		try {
			await get(`/applications/${id}/check?domain=${domain}`);
			addToast({
				message: 'DNS configuration is valid.',
				type: 'success'
			});
			isWWW ? (isWWWDomainOK = true) : (isNonWWWDomainOK = true);
			return true;
		} catch (error) {
			errorNotification(error);
			isWWW ? (isWWWDomainOK = false) : (isNonWWWDomainOK = false);
			return false;
		}
	}
	async function getGitlabToken() {
		return await new Promise<void>((resolve, reject) => {
			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=${getAPIUrl()}/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);
					$appSession.tokens.gitlab = localStorage.getItem('gitLabToken');
					localStorage.removeItem('gitLabToken');
					resolve();
				}
			}, 100);
		});
	}
	async function reloadCompose() {
		if (loading.reloadCompose) return;
		loading.reloadCompose = true;
		const composeLocation = application.dockerComposeFileLocation.startsWith('/')
			? application.dockerComposeFileLocation
			: `/${application.dockerComposeFileLocation}`;
		try {
			if (application.gitSource.type === 'github') {
				const headers = isPublicRepository
					? {}
					: {
							Authorization: `token ${$appSession.tokens.github}`
					  };
				const data = await get(
					`${apiUrl}/repos/${repository}/contents/${composeLocation}?ref=${branch}`,
					{
						...headers,
						'If-None-Match': '',
						Accept: 'application/vnd.github.v2.json'
					}
				);
				if (data?.content) {
					const content = atob(data.content);
					let dockerComposeFileContent = JSON.stringify(yaml.load(content) || null);
					let dockerComposeFileContentJSON = JSON.parse(dockerComposeFileContent);
					dockerComposeServices = normalizeDockerServices(dockerComposeFileContentJSON?.services);
					application.dockerComposeFile = dockerComposeFileContent;
					await handleSubmit(false);
				}
			}
			if (application.gitSource.type === 'gitlab') {
				if (!$appSession.tokens.gitlab) {
					await getGitlabToken();
				}
				const headers = isPublicRepository
					? {}
					: {
							Authorization: `Bearer ${$appSession.tokens.gitlab}`
					  };
				const url = isPublicRepository
					? ``
					: `/v4/projects/${application.projectId}/repository/tree`;
				const files = await get(`${apiUrl}${url}`, {
					...headers
				});
				const dockerComposeFileYml = files.find(
					(file: { name: string; type: string }) =>
						file.name === composeLocation && file.type === 'blob'
				);
				const id = dockerComposeFileYml.id;

				const data = await get(
					`${apiUrl}/v4/projects/${application.projectId}/repository/blobs/${id}`,
					{
						...headers
					}
				);
				if (data?.content) {
					const content = atob(data.content);
					let dockerComposeFileContent = JSON.stringify(yaml.load(content) || null);
					let dockerComposeFileContentJSON = JSON.parse(dockerComposeFileContent);
					dockerComposeServices = normalizeDockerServices(dockerComposeFileContentJSON?.services);
					application.dockerComposeFile = dockerComposeFileContent;
					await handleSubmit(false);
				}
			}
			originalDockerComposeFileLocation = application.dockerComposeFileLocation;
			addToast({
				message: 'Compose file reloaded.',
				type: 'success'
			});
		} catch (error: any) {
			if (error.message === 'Not Found') {
				error.message = `Can't find ${application.dockerComposeFileLocation} file.`;
				errorNotification(error);
				throw error;
			}
			errorNotification(error);
		} finally {
			loading.reloadCompose = false;
		}
	}
	$: if ($status.application.statuses) {
		for (const service of dockerComposeServices) {
			getStatus(service);
		}
	}
	function getStatus(service: any) {
		let foundStatus = null;
		const foundService = $status.application.statuses.find(
			(s: any) => s.name === `${application.id}-${service.name}`
		);
		if (foundService) {
			const statusText = foundService?.status;
			if (statusText?.isRunning) {
				foundStatus = 'Running';
			}
			if (statusText?.isExited) {
				foundStatus = 'Exited';
			}
			if (statusText?.isRestarting) {
				foundStatus = 'Restarting';
			}
		}
		statues[service.name] = foundStatus || 'Stopped';
	}
</script>

<div class="w-full">
	<form on:submit|preventDefault={() => handleSubmit()}>
		<div class="mx-auto w-full">
			<div class="flex flex-row border-b border-coolgray-500 mb-6 space-x-2">
				<div class="title font-bold pb-3">General</div>
				{#if $appSession.isAdmin}
					<button
						class="btn btn-sm  btn-primary"
						type="submit"
						class:loading={loading.save}
						class:bg-orange-600={forceSave}
						class:hover:bg-orange-400={forceSave}
						disabled={loading.save}>{$t('forms.save')}</button
					>
				{/if}
			</div>
			<div class="grid grid-flow-row gap-2 px-4">
				<div class="mt-2 grid grid-cols-2 items-center">
					<label for="name">{$t('forms.name')}</label>
					<input name="name" id="name" class="w-full" bind:value={application.name} required />
				</div>
				<div class="grid grid-cols-2 items-center">
					<label for="gitSource">{$t('application.git_source')}</label>
					{#if isDisabled || application.settings.isPublicRepository}
						<input
							disabled={isDisabled || application.settings.isPublicRepository}
							class="w-full"
							value={application.gitSource?.name}
						/>
					{:else}
						<a
							href={`/applications/${id}/configuration/source?from=/applications/${id}`}
							class="no-underline"
							><input
								value={application.gitSource?.name}
								id="gitSource"
								class="cursor-pointer hover:bg-coolgray-500 w-full"
							/></a
						>
					{/if}
				</div>
				<div class="grid grid-cols-2 items-center">
					<label for="repository">Git commit</label>
					<div class="flex gap-2">
						<input
							class="w-full"
							disabled={isDisabled}
							placeholder="default: latest commit"
							bind:value={application.gitCommitHash}
						/>
						<a href={application.gitSource.htmlUrl}/{application.repository}/commits/{application.branch} target="_blank" rel="noreferrer" class="btn btn-primary text-xs" >Commits<svg
							xmlns="http://www.w3.org/2000/svg"
							fill="currentColor"
							viewBox="0 0 24 24"
							stroke-width="3"
							stroke="currentColor"
							class="w-3 h-3 text-white ml-2"
						>
							<path
								stroke-linecap="round"
								stroke-linejoin="round"
								d="M4.5 19.5l15-15m0 0H8.25m11.25 0v11.25"
							/>
						</svg></a>
					</div>
				</div>
				<div class="grid grid-cols-2 items-center">
					<label for="repository">{$t('application.git_repository')}</label>
					{#if isDisabled || application.settings.isPublicRepository}
						<input
							class="w-full"
							disabled={isDisabled || application.settings.isPublicRepository}
							value="{application.repository}/{application.branch}"
						/>
					{:else}
						<a
							href={`/applications/${id}/configuration/repository?from=/applications/${id}&to=/applications/${id}/configuration/buildpack`}
							class="no-underline"
							><input
								value="{application.repository}/{application.branch}"
								id="repository"
								class="cursor-pointer hover:bg-coolgray-500 w-full"
							/></a
						>
					{/if}
				</div>
				<div class="grid grid-cols-2 items-center">
					<label for="registry">Docker Registry</label>
					{#if isDisabled}
						<input
							class="capitalize w-full"
							disabled={isDisabled}
							value={application.dockerRegistry.name}
						/>
					{:else}
						<a
							href={`/applications/${id}/configuration/registry?from=/applications/${id}`}
							class="no-underline"
						>
							<input
								value={application.dockerRegistry.name}
								id="registry"
								class="cursor-pointer hover:bg-coolgray-500 capitalize w-full"
							/></a
						>
					{/if}
				</div>
				<div class="grid grid-cols-2 items-center">
					<label for="buildPack">{$t('application.build_pack')} </label>
					{#if isDisabled}
						<input class="capitalize w-full" disabled={isDisabled} value={application.buildPack} />
					{:else}
						<a
							href={`/applications/${id}/configuration/buildpack?from=/applications/${id}`}
							class="no-underline"
						>
							<input
								value={application.buildPack}
								id="buildPack"
								class="cursor-pointer hover:bg-coolgray-500 capitalize w-full"
							/></a
						>
					{/if}
				</div>
				<div class="grid grid-cols-2 items-center">
					<label for="destination">{$t('application.destination')}</label>
					<div class="no-underline">
						<input
							value={application.destinationDocker.name}
							id="destination"
							disabled
							class="bg-transparent w-full"
						/>
					</div>
				</div>
				{#if application.buildPack !== 'compose'}
					<div class="grid grid-cols-2 items-center">
						<Setting
							id="isBot"
							isCenter={false}
							bind:setting={isBot}
							on:click={() => changeSettings('isBot')}
							title="Is your application a bot?"
							description="You can deploy applications without domains or make them to listen on the <span class='text-settings font-bold'>Exposed Port</span>.<br></Setting><br>Useful to host <span class='text-settings font-bold'>Twitch bots, regular jobs, or anything that does not require an incoming HTTP connection.</span>"
							disabled={isDisabled}
						/>
					</div>
				{/if}
				{#if !isBot && application.buildPack !== 'compose'}
					<div class="grid grid-cols-2 items-center">
						<label for="fqdn"
							>{$t('application.url_fqdn')}
							<Explainer
								explanation={"If you specify <span class='text-settings font-bold'>https</span>, the application will be accessible only over https.<br>SSL certificate will be generated automatically.<br><br>If you specify <span class='text-settings font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application.<br><br><span class='text-settings font-bold'>You must set your DNS to point to the server IP in advance.</span>"}
							/>
						</label>
						<div>
							<input
								bind:this={fqdnEl}
								class="w-full"
								required={!application.settings?.isBot}
								readonly={isDisabled}
								disabled={isDisabled}
								name="fqdn"
								id="fqdn"
								class:border={!application.settings?.isBot && !application.fqdn}
								class:border-red-500={!application.settings?.isBot && !application.fqdn}
								bind:value={application.fqdn}
								pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
								placeholder="eg: https://coollabs.io"
							/>
							{#if forceSave}
								<div class="flex-col space-y-2 pt-4 text-center">
									{#if isNonWWWDomainOK}
										<button
											class="btn btn-sm bg-green-600 hover:bg-green-500"
											on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
											>DNS settings for {nonWWWDomain} is OK, click to recheck.</button
										>
									{:else}
										<button
											class="btn btn-sm bg-red-600 hover:bg-red-500"
											on:click|preventDefault={() => isDNSValid(getDomain(nonWWWDomain), false)}
											>DNS settings for {nonWWWDomain} is invalid, click to recheck.</button
										>
									{/if}
									{#if dualCerts}
										{#if isWWWDomainOK}
											<button
												class="btn btn-sm bg-green-600 hover:bg-green-500"
												on:click|preventDefault={() =>
													isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
												>DNS settings for www.{nonWWWDomain} is OK, click to recheck.</button
											>
										{:else}
											<button
												class="btn btn-sm bg-red-600 hover:bg-red-500"
												on:click|preventDefault={() =>
													isDNSValid(getDomain(`www.${nonWWWDomain}`), true)}
												>DNS settings for www.{nonWWWDomain} is invalid, click to recheck.</button
											>
										{/if}
									{/if}
								</div>
							{/if}
						</div>
					</div>
					<div class="grid grid-cols-2 items-center pb-4">
						<Setting
							id="dualCerts"
							dataTooltip={$t('forms.must_be_stopped_to_modify')}
							disabled={isDisabled}
							isCenter={false}
							bind:setting={dualCerts}
							title={$t('application.ssl_www_and_non_www')}
							description="Generate certificates for both www and non-www. <br>You need to have <span class='font-bold text-settings'>both DNS entries</span> set in advance.<br><br>Useful if you expect to have visitors on both."
							on:click={() => !isDisabled && changeSettings('dualCerts')}
						/>
					</div>
					{#if isHttps && application.buildPack !== 'compose'}
						<div class="grid grid-cols-2 items-center pb-4">
							<Setting
								id="isCustomSSL"
								isCenter={false}
								bind:setting={isCustomSSL}
								title="Use Custom SSL Certificate"
								description="Use Custom SSL Certificated added in the Settings/SSL Certificates section. <br><br>By default, the SSL certificate is generated automatically through Let's Encrypt"
								on:click={() => changeSettings('isCustomSSL')}
							/>
						</div>
					{/if}
				{/if}
			</div>
			{#if application.buildPack !== 'compose'}
				<div class="title font-bold pb-3 pt-10 border-b border-coolgray-500 mb-6">
					Configuration
				</div>
				<div class="grid grid-flow-row gap-2 px-4 pr-5">
					{#if application.buildCommand || application.buildPack === 'rust' || application.buildPack === 'laravel'}
						<div class="grid grid-cols-2 items-center">
							<label for="baseBuildImage"
								>{$t('application.base_build_image')}
								<Explainer
									explanation={application.buildPack === 'laravel'
										? 'For building frontend assets with webpack.'
										: 'Image that will be used during the build process.'}
								/>
							</label>
							<div class="custom-select-wrapper">
								<Select
									{isDisabled}
									containerClasses={isDisabled && containerClass()}
									id="baseBuildImages"
									showIndicator={!isDisabled}
									items={application.baseBuildImages}
									on:select={selectBaseBuildImage}
									value={application.baseBuildImage}
									isClearable={false}
								/>
							</div>
						</div>
					{/if}
					{#if application.buildPack !== 'docker'}
						<div class="grid grid-cols-2 items-center">
							<label for="baseImage"
								>{$t('application.base_image')}
								<Explainer explanation={'Image that will be used for the deployment.'} /></label
							>
							<div class="custom-select-wrapper">
								<Select
									{isDisabled}
									containerClasses={isDisabled && containerClass()}
									id="baseImages"
									showIndicator={!isDisabled}
									items={application.baseImages}
									on:select={selectBaseImage}
									value={application.baseImage}
									isClearable={false}
								/>
							</div>
						</div>
					{/if}
					{#if application.buildPack !== 'docker' && (application.buildPack === 'nextjs' || application.buildPack === 'nuxtjs')}
						<div class="grid grid-cols-2 items-center pb-8">
							<label for="deploymentType"
								>Deployment Type
								<Explainer
									explanation={"Defines how to deploy your application. <br><br><span class='text-green-500 font-bold'>Static</span> is for static websites, <span class='text-green-500 font-bold'>node</span> is for server-side applications."}
								/></label
							>
							<div class="custom-select-wrapper">
								<Select
									{isDisabled}
									containerClasses={isDisabled && containerClass()}
									id="deploymentTypes"
									showIndicator={!isDisabled}
									items={['static', 'node']}
									on:select={selectDeploymentType}
									value={application.deploymentType}
									isClearable={false}
								/>
							</div>
						</div>
					{/if}
					{#if $features.beta}
						{#if !application.settings?.isBot && !application.settings?.isPublicRepository}
							<div class="grid grid-cols-2 items-center">
								<Setting
									id="isDBBranching"
									isCenter={false}
									bind:setting={isDBBranching}
									on:click={() => changeSettings('isDBBranching')}
									title="Enable DB Branching"
									description="Enable DB Branching"
								/>
							</div>
							{#if isDBBranching}
								<button
									on:click|stopPropagation|preventDefault={() =>
										goto(`/applications/${id}/configuration/database`)}
									class="btn btn-sm">Configure Connected Database</button
								>
								{#if application.connectedDatabase}
									<div class="grid grid-cols-2 items-center">
										<label for="baseImage"
											>Base Database
											<Explainer
												explanation={'The name of the database that will be used as base when branching.'}
											/></label
										>
										<input
											name="baseDatabaseBranch"
											required
											id="baseDatabaseBranch"
											bind:value={baseDatabaseBranch}
										/>
									</div>
									<div class="text-center bg-green-600 rounded">
										Connected to {application.connectedDatabase.databaseId}
									</div>
								{/if}
							{/if}
						{/if}
					{/if}

					{#if application.buildPack === 'python'}
						<div class="grid grid-cols-2 items-center">
							<label for="pythonModule">WSGI / ASGI</label>
							<div class="custom-select-wrapper">
								<Select
									id="wsgi"
									items={wsgis}
									on:select={selectWSGI}
									value={application.pythonWSGI}
								/>
							</div>
						</div>

						<div class="grid grid-cols-2 items-center">
							<label for="pythonModule">Module</label>
							<input
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="pythonModule"
								id="pythonModule"
								required
								class="w-full"
								bind:value={application.pythonModule}
								placeholder={application.pythonWSGI?.toLowerCase() !== 'none' ? 'main' : 'main.py'}
							/>
						</div>
						{#if application.pythonWSGI?.toLowerCase() === 'gunicorn'}
							<div class="grid grid-cols-2 items-center">
								<label for="pythonVariable">Variable</label>
								<input
									disabled={isDisabled}
									readonly={!$appSession.isAdmin}
									name="pythonVariable"
									id="pythonVariable"
									required
									class="w-full"
									bind:value={application.pythonVariable}
									placeholder="default: app"
								/>
							</div>
						{/if}
						{#if application.pythonWSGI?.toLowerCase() === 'uvicorn'}
							<div class="grid grid-cols-2 items-center">
								<label for="pythonVariable">Variable</label>
								<input
									disabled={isDisabled}
									readonly={!$appSession.isAdmin}
									name="pythonVariable"
									id="pythonVariable"
									required
									class="w-full"
									bind:value={application.pythonVariable}
									placeholder="default: app"
								/>
							</div>
						{/if}
					{/if}
					{#if !staticDeployments.includes(application.buildPack)}
						<div class="grid grid-cols-2 items-center pt-4">
							<label for="port"
								>{$t('forms.port')}
								<Explainer
									explanation={'The port your application listens inside the docker container.'}
								/></label
							>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="port"
								id="port"
								bind:value={application.port}
								placeholder="{$t('forms.default')}: 'python' ? '8000' : '3000'"
							/>
						</div>
					{/if}
					<div class="grid grid-cols-2 items-center pb-4">
						<label for="exposePort"
							>Exposed Port <Explainer
								explanation={'You can expose your application to a port on the host system.<br><br>Useful if you would like to use your own reverse proxy or tunnel and also in development mode. Otherwise leave empty.'}
							/></label
						>
						<input
							class="w-full"
							disabled={isDisabled}
							readonly={!$appSession.isAdmin}
							name="exposePort"
							id="exposePort"
							bind:value={application.exposePort}
							placeholder="12345"
						/>
					</div>
					{#if !notNodeDeployments.includes(application.buildPack)}
						<div class="grid grid-cols-2 items-center">
							<label for="installCommand">{$t('application.install_command')}</label>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="installCommand"
								id="installCommand"
								bind:value={application.installCommand}
								placeholder="{$t('forms.default')}: yarn install"
							/>
						</div>
						<div class="grid grid-cols-2 items-center">
							<label for="buildCommand">{$t('application.build_command')}</label>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="buildCommand"
								id="buildCommand"
								bind:value={application.buildCommand}
								placeholder="{$t('forms.default')}: yarn build"
							/>
						</div>
						<div class="grid grid-cols-2 items-center pb-8">
							<label for="startCommand">{$t('application.start_command')}</label>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="startCommand"
								id="startCommand"
								bind:value={application.startCommand}
								placeholder="{$t('forms.default')}: yarn start"
							/>
						</div>
					{/if}
					{#if application.buildPack === 'deno'}
						<div class="grid grid-cols-2 items-center">
							<label for="denoMainFile">Main File</label>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="denoMainFile"
								id="denoMainFile"
								bind:value={application.denoMainFile}
								placeholder="default: main.ts"
							/>
						</div>
						<div class="grid grid-cols-2 items-center">
							<label for="denoOptions"
								>Arguments <Explainer
									explanation={"List of arguments to pass to <span class='text-settings font-bold'>deno run</span> command. Could include permissions, configurations files, etc."}
								/></label
							>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="denoOptions"
								id="denoOptions"
								bind:value={application.denoOptions}
								placeholder="eg: --allow-net --allow-hrtime --config path/to/file.json"
							/>
						</div>
					{/if}
					{#if application.buildPack !== 'laravel'}
						<div class="grid grid-cols-2 items-center">
							<div class="flex-col">
								<label for="baseDirectory"
									>{$t('forms.base_directory')}
									<Explainer
										explanation={"Directory to use as the base for all commands.<br>Could be useful with <span class='text-settings font-bold'>monorepos</span>."}
									/></label
								>
							</div>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="baseDirectory"
								id="baseDirectory"
								bind:value={application.baseDirectory}
								placeholder="{$t('forms.default')}: /"
							/>
						</div>
					{/if}
					{#if application.buildPack === 'docker'}
						<div class="grid grid-cols-2 items-center pb-4">
							<label for="dockerFileLocation" class=""
								>Dockerfile Location <Explainer
									explanation={"Should be absolute path, like <span class='text-settings font-bold'>/data/Dockerfile</span> or <span class='text-settings font-bold'>/Dockerfile.</span>"}
								/></label
							>
							<div class="form-control w-full">
								<input
									class="w-full input"
									disabled={isDisabled}
									readonly={!$appSession.isAdmin}
									name="dockerFileLocation"
									id="dockerFileLocation"
									bind:value={application.dockerFileLocation}
									placeholder="default: /Dockerfile"
								/>
								{#if application.baseDirectory}
									<label class="label">
										<span class="label-text-alt text-xs"
											>Path: {application.baseDirectory.replace(
												/^\/$/,
												''
											)}{application.dockerFileLocation}</span
										>
									</label>
								{/if}
							</div>
						</div>
					{/if}
					{#if !notNodeDeployments.includes(application.buildPack)}
						<div class="grid grid-cols-2 items-center">
							<div class="flex-col">
								<label for="publishDirectory"
									>{$t('forms.publish_directory')}
									<Explainer
										explanation={"Directory containing all the assets for deployment. <br> For example: <span class='text-settings font-bold'>dist</span>,<span class='text-settings font-bold'>_site</span> or <span class='text-settings font-bold'>public</span>."}
									/></label
								>
							</div>

							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="publishDirectory"
								id="publishDirectory"
								required={application.deploymentType === 'static'}
								bind:value={application.publishDirectory}
								placeholder=" {$t('forms.default')}: /"
							/>
						</div>
					{/if}
				</div>
			{:else}
				<div class="title font-bold pb-3 pt-10 border-b border-coolgray-500 mb-6">
					Stack <Beta />
					{#if $appSession.isAdmin}
						<button
							class="btn btn-sm btn-primary"
							class:loading={loading.reloadCompose}
							disabled={loading.reloadCompose}
							on:click|preventDefault={reloadCompose}>Reload Docker Compose File</button
						>
					{/if}
				</div>
				<div class="grid grid-flow-row gap-2">
					<div class="grid grid-cols-2 items-center px-8 pb-4">
						<label for="dockerComposeFileLocation"
							>Docker Compose File Location
							<Explainer
								explanation="You can specify a custom docker compose file location. <br> Should be absolute path, like <span class='text-settings font-bold'>/data/docker-compose.yml</span> or <span class='text-settings font-bold'>/docker-compose.yml.</span>"
							/>
						</label>
						<div>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="dockerComposeFileLocation"
								id="dockerComposeFileLocation"
								bind:value={application.dockerComposeFileLocation}
								placeholder="eg: /docker-compose.yml"
							/>
						</div>
					</div>
					{#each dockerComposeServices as service}
						<div
							class="grid items-center bg-coolgray-100 rounded border border-coolgray-300 p-2 px-4"
						>
							<div class="text-xl font-bold uppercase">
								{service.name}
								<span
									class="badge rounded text-white"
									class:text-red-500={statues[service.name] === 'Exited' ||
										statues[service.name] === 'Stopped'}
									class:text-yellow-400={statues[service.name] === 'Restarting'}
									class:text-green-500={statues[service.name] === 'Running'}
									>{statues[service.name] || 'Loading...'}</span
								>
							</div>
							<div class="text-xs">{application.id}-{service.name}</div>
						</div>

						<div class="grid grid-cols-2 items-center px-8">
							<label for="fqdn"
								>{$t('application.url_fqdn')}
								<Explainer
									explanation={"If you specify <span class='text-settings font-bold'>https</span>, the application will be accessible only over https.<br>SSL certificate will be generated automatically.<br><br>If you specify <span class='text-settings font-bold'>www</span>, the application will be redirected (302) from non-www and vice versa.<br><br>To modify the domain, you must first stop the application.<br><br><span class='text-settings font-bold'>You must set your DNS to point to the server IP in advance.</span>"}
								/>
							</label>
							<div>
								<input
									class="w-full"
									disabled={isDisabled}
									readonly={!$appSession.isAdmin}
									name="fqdn"
									id="fqdn"
									bind:value={dockerComposeConfiguration[service.name].fqdn}
									pattern="^https?://([a-z0-9]+(-[a-z0-9]+)*\.)+[a-z]{'{'}2,{'}'}$"
									placeholder="eg: https://coollabs.io"
								/>
							</div>
						</div>
						<div class="grid grid-cols-2 items-center px-8">
							<label for="destinationdns"
								>Internal DNS on the deployed Destination
								<Explainer
									explanation={'You can use these DNS names to access the application from other resources in your Destination.'}
								/>
							</label>
							<input
								for="destinationdns"
								class="w-full"
								disabled
								readonly
								value={`${application.id}-${service.name}`}
							/>
						</div>
						<div class="grid grid-cols-2 items-center px-8">
							<label for="stackdns"
								>Internal DNS in the current stack
								<Explainer
									explanation={'You can use these DNS names to access the application from this stack.'}
								/>
							</label>
							<input for="stackdns" class="w-full" disabled readonly value={service.name} />
						</div>
						<div class="grid grid-cols-2 items-center px-8 pb-4">
							<label for="port"
								>{$t('forms.port')}
								<Explainer
									explanation={'The port your application listens inside the docker container.'}
								/></label
							>
							<input
								class="w-full"
								disabled={isDisabled}
								readonly={!$appSession.isAdmin}
								name="port"
								id="port"
								required={!!dockerComposeConfiguration[service.name].fqdn}
								bind:value={dockerComposeConfiguration[service.name].port}
							/>
						</div>
					{/each}
				</div>
			{/if}
		</div>
	</form>
</div>
