<template>
	<div class="top-0 z-10 shrink-0">
		<Header>
			<FBreadcrumbs
				:items="[
					{
						label: '创建站点',
					},
				]"
			/>
		</Header>

		<div class="m-12 mx-auto max-w-2xl px-5">
			<div
				v-if="$resources.installAppOptions.loading"
				class="py-4 text-base text-gray-600"
			>
				加载中...
			</div>
			<div v-else class="space-y-6">
				<div class="mb-12 flex">
					<img
						:src="appDoc.image"
						class="h-12 w-12 rounded-lg border"
						:alt="appDoc.name"
					/>
					<div class="my-1 ml-4 flex flex-col justify-between">
						<h1 class="text-lg font-semibold">{{ appDoc.title }}</h1>
						<p class="text-sm text-gray-600">{{ appDoc.description }}</p>
					</div>
				</div>

				<div class="space-y-12">
					<div v-if="$team.pg.onboarding.site_created">
						<div v-if="plans.length">
							<div class="flex items-center justify-between">
								<h2 class="text-base font-medium leading-6 text-gray-900">
									选择计划
								</h2>
							</div>
							<div class="mt-2">
								<PlansCards v-model="selectedPlan" :plans="plans" />
							</div>
						</div>

						<div v-if="options.private_groups.length">
							<h2 class="text-base font-medium leading-6 text-gray-900">
								选择站点分组
								<span class="text-sm text-gray-500"> (可选) </span>
							</h2>
							<div class="mt-2 w-full space-y-2">
								<FormControl
									type="autocomplete"
									:options="
										options.private_groups.map((b) => ({
											label: b.title,
											value: b.name,
										}))
									"
									v-model="selectedGroup"
								/>
							</div>
						</div>
					</div>

					<div>
						<h2 class="text-base font-medium leading-6 text-gray-900">
							选择区域
						</h2>
						<div class="mt-2 w-full space-y-2">
							<div class="grid grid-cols-2 gap-3">
								<button
									v-for="c in regions"
									:key="c.name"
									@click="cluster = c.name"
									:class="[
										cluster === c.name
											? 'border-gray-900 ring-1 ring-gray-900 hover:bg-gray-100'
											: 'bg-white text-gray-900  hover:bg-gray-50',
										'flex w-full items-center rounded border p-3 text-left text-base text-gray-900',
									]"
								>
									<div class="flex w-full items-center justify-between">
										<div class="flex w-full items-center space-x-2">
											<img :src="c.image" class="h-5 w-5" />
											<span class="text-sm font-medium">
												{{ c.title }}
											</span>
										</div>
										<Badge v-if="c.beta" :label="c.beta ? 'Beta' : ''" />
									</div>
								</button>
							</div>
						</div>
					</div>

					<div>
						<h2 class="text-base font-medium leading-6 text-gray-900">
							输入子域名
						</h2>
						<div class="mt-2 items-center">
							<div class="col-span-2 flex w-full">
								<input
									class="dark:[color-scheme:dark] z-10 h-7 w-full flex-1 rounded rounded-r-none border border-[--surface-gray-2] bg-surface-gray-2 py-1.5 pl-2 pr-2 text-base text-ink-gray-8 placeholder-ink-gray-4 transition-colors hover:border-outline-gray-modals hover:bg-surface-gray-3 focus:border-outline-gray-4 focus:bg-surface-white focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3"
									placeholder="子域名"
									v-model="subdomain"
								/>
								<div
									class="flex items-center rounded-r bg-gray-100 px-4 text-base"
								>
									.{{ options.domain }}
								</div>
							</div>
						</div>

						<div class="mt-1">
<ErrorMessage :message="$resources.subdomainExists.error" />
							<div
								v-if="$resources.subdomainExists.loading"
								class="text-sm text-gray-600"
							>
								正在检查...
							</div>
							<template
								v-else-if="
									!$resources.subdomainExists.error &&
									$resources.subdomainExists.data != null
								"
							>
								<div
									v-if="$resources.subdomainExists.data"
									class="text-sm text-green-600"
								>
									{{ subdomain }}.{{ options.domain }} 可用
								</div>
								<div v-else class="text-sm text-red-600">
									{{ subdomain }}.{{ options.domain }} 不可用
								</div>
							</template>
						</div>
					</div>
					<div class="flex flex-col space-y-4">
						<FormControl
							class="checkbox"
							type="checkbox"
							v-model="agreedToRegionConsent"
							:label="`我同意我所选区域的法律 ${
								this.cluster ? `(${this.cluster})` : ''
							} 适用于我和 Jingrow。`"
						/>
						<ErrorMessage class="my-2" :message="$resources.newSite.error" />
						<Button
							class="w-full"
							variant="solid"
							:disabled="
								!agreedToRegionConsent || !$resources.subdomainExists.data
							"
							@click="$resources.newSite.submit()"
							:loading="$resources.newSite.loading"
						>
							创建站点并安装 {{ appDoc.title }}
						</Button>
					</div>
				</div>
				<div class="flex space-x-1">
					<div class="text-sm text-gray-600">
						想要在现有站点或 站点分组上安装 <b>{{ appDoc.title }}</b> 吗？
					</div>
					<a
						class="text-sm underline"
						href="https://jingrow.com/docs/installing-an-app"
						target="_blank"
					>
						阅读文档
					</a>
				</div>
			</div>
		</div>
	</div>
</template>

<script>
import { Breadcrumbs, debounce } from 'jingrow-ui';
import Header from '../components/Header.vue';
import PlansCards from '../components/PlansCards.vue';
import { DashboardError } from '../utils/error';
import { validateSubdomain } from '../utils/site';

export default {
	name: 'InstallApp',
	props: {
		app: {
			type: String,
			required: true,
		},
	},
	pageMeta() {
		return {
			title: `安装 ${this.appDoc.title} - Jingrow`,
		};
	},
	components: {
		FBreadcrumbs: Breadcrumbs,
		PlansCards,
		Header,
	},
	data() {
		return {
			plan: '',
			subdomain: '',
			cluster: null,
			selectedPlan: null,
			selectedGroup: null,
			agreedToRegionConsent: false,
			sitePlan: null,
			trial: false,
		};
	},
	watch: {
		subdomain: {
			handler: debounce(function (value) {
				let invalidMessage = validateSubdomain(value);
				this.$resources.subdomainExists.error = invalidMessage;
				if (!invalidMessage) {
					this.$resources.subdomainExists.submit();
				}
			}, 500),
		},
	},
	resources: {
		app() {
			return {
				url: 'jcloud.api.marketplace.get',
				params: {
					app: this.app,
				},
				auto: true,
			};
		},
		installAppOptions() {
			return {
				url: 'jcloud.api.marketplace.get_install_app_options',
				auto: true,
				params: {
					marketplace_app: this.app,
				},
				initialData: {
					domain: '',
					plans: [],
					clusters: [],
					private_groups: [],
				},
				async onSuccess() {
					this.cluster = await this.getClosestCluster();
					if (this.$resources.installAppOptions.data?.plans.length > 0) {
						this.selectedPlan = this.$resources.installAppOptions.data.plans[0];
					}
				},
			};
		},
		subdomainExists() {
			return {
				url: 'jcloud.api.site.exists',
				makeParams() {
					return {
						domain: this.$resources.installAppOptions.data?.domain,
						subdomain: this.subdomain,
					};
				},
				validate() {
					let error = validateSubdomain(this.subdomain);
					if (error) {
						throw new DashboardError(error);
					}
				},
transform(data) {
					return !Boolean(data);
				},
			};
		},
		getTrialPlan() {
			return {
				url: 'jcloud.api.site.get_trial_plan',
				auto: true,
			};
		},
		newSite() {
			if (!this.options) return;

			return {
				url: 'jcloud.api.marketplace.create_site_for_app',
				makeParams() {
					this.sitePlan = this.selectedGroup
						? this.options.private_site_plan
						: this.options.public_site_plan;

					if (!this.$team.pg.onboarding.site_created) {
						this.sitePlan = this.trialPlan;
						this.trial = true;
					}
					return {
						subdomain: this.subdomain,
						site_plan: this.sitePlan,
						apps: [
							{
								app: 'jingrow',
							},
							{
								app: this.app,
								plan: this.selectedPlan?.name,
							},
						],
						cluster: this.cluster,
						group: this.selectedGroup?.value,
						trial: this.trial,
					};
				},
				validate() {
					if (
						!this.$team.pg.payment_mode &&
						(this.$team.pg.onboarding.site_created ||
							!this.appDoc.show_for_new_site)
					) {
						throw new DashboardError('请添加有效的支付方式');
					}
					if (!this.selectedPlan && this.plans.length > 0) {
						throw new DashboardError('请选择一个计划');
					}
					if (!this.subdomain) {
						throw new DashboardError('请输入子域名');
					}
					if (!this.agreedToRegionConsent) {
						throw new DashboardError(
							'请同意上述同意书以创建站点',
						);
					}
				},
				onSuccess: (pg) => {
					if (pg.pagetype === 'Site') {
						this.$router.push({
							name: 'Site Jobs',
							params: { name: pg.name },
						});
					} else if (pg.pagetype === 'Site Group Deploy') {
						this.$router.push({
							name: 'CreateSiteForMarketplaceApp',
							params: { app: this.app },
							query: { siteGroupDeployName: pg.name },
						});
					}
				},
			};
		},
	},
	methods: {
		async getClosestCluster() {
			if (this.closestCluster) return this.closestCluster;
			let proxyServers = this.options.clusters
				.flatMap((c) => c.proxy_server || [])
				.map((server) => server.name);

			if (proxyServers.length > 0) {
				this.findingClosestServer = true;
				let promises = proxyServers.map((server) => this.getPingTime(server));
				let results = await Promise.allSettled(promises);
				let fastestServer = results.reduce((a, b) =>
					a.value.pingTime < b.value.pingTime ? a : b,
				);
				let closestServer = fastestServer.value.server;
				let closestCluster = this.options.clusters.find(
					(c) => c.proxy_server?.name === closestServer,
				);
				if (!this.closestCluster) {
					this.closestCluster = closestCluster.name;
				}
				this.findingClosestServer = false;
			} else if (proxyServers.length === 1) {
				this.closestCluster = this.options.clusters[0].name;
			}
			return this.closestCluster;
		},
		async getPingTime(server) {
			let pingTime = 999999;
			try {
				let t1 = new Date().getTime();
				let r = await fetch(`https://${server}`);
				let t2 = new Date().getTime();
				pingTime = t2 - t1;
			} catch (error) {
				console.warn(error);
			}
			return { server, pingTime };
		},
	},
	computed: {
		appDoc() {
			return this.$resources.app.data || {};
		},
		options() {
			return this.$resources.installAppOptions.data;
		},
		plans() {
			if (!this.$resources?.installAppOptions) return [];
			return this.options.plans.map((plan) => ({
				...plan,
				label:
					plan.price_cny === 0 || plan.price_usd === 0
						? '免费'
						: `${this.$format.userCurrency(
								this.$team.pg.currency === 'CNY'
									? plan.price_cny
									: plan.price_usd,
							)}/月`,
				sublabel: ' ',
				features: plan.features.map((f) => ({
					value: f,
					icon: 'check-circle',
				})),
			}));
		},
regions() {
			if (!this.selectedGroup) {
				return this.options.clusters;
			} else {
				return this.options.private_groups.find(
					(g) => g.name === this.selectedGroup.value,
				).clusters;
			}
		},
		trialPlan() {
			return this.$resources.getTrialPlan.data;
		},
	},
};
</script>