<script lang="ts">
	import { page } from "$app/state";
	import { getAuth } from "$lib/auth.svelte";
	import { createAppviewClient } from "$lib/api/appview";
	import { ClientResponseError } from "$lib/api/client";
	import { getDomainClaim, claimDomain, releaseDomain } from "$lib/api/sites";
	import Button from "$lib/components/ui/Button.svelte";
	import Input from "$lib/components/ui/Input.svelte";
	import Tag from "$lib/components/ui/Tag.svelte";
	import ErrorAlert from "$lib/components/ui/Error.svelte";
	import Skeleton from "$lib/components/ui/Skeleton.svelte";
	import SettingsEmpty from "../SettingsEmpty.svelte";
	import SettingsHeader from "../SettingsHeader.svelte";
	import SettingsToolbar from "../SettingsToolbar.svelte";
	import SettingsList from "../SettingsList.svelte";
	import SettingsEntry from "../SettingsEntry.svelte";
	import FormRow from "../FormRow.svelte";
	import DocsButton from "../DocsButton.svelte";
	import { createAction, createLoad } from "$lib/action.svelte";
	import Globe from "$icon/globe";
	import Check from "$icon/check";
	import Unlink from "$icon/unlink";
	import Plus from "$icon/plus";

	const auth = getAuth();
	const apiUrl = $derived(page.data.publicConfig?.apiUrl as string | undefined);
	const sitesDomain = $derived((page.data.publicConfig?.sitesDomain as string | undefined) ?? "");

	let subdomain = $state("");

	// prefer the xrpc error's message/name over a generic client error string.
	const errMessage = (err: unknown, fallback: string): string => {
		if (err instanceof ClientResponseError) return err.description || err.error || fallback;
		return err instanceof Error ? err.message : fallback;
	};
	const loaded = createLoad(
		async (): Promise<string | null> => {
			const agent = auth.agent;
			const url = apiUrl;
			if (!agent || !url) return null;
			const ctx = createAppviewClient({ apiUrl: url, agent });
			return getDomainClaim(ctx);
		},
		(cause) => errMessage(cause, "Failed to load your sites domain.")
	);

	const claim = createAction(
		async (event: SubmitEvent) => {
			event.preventDefault();
			const agent = auth.agent;
			const url = apiUrl;
			const domain = subdomain.trim();
			if (!agent || !url || !domain) return;
			const ctx = createAppviewClient({ apiUrl: url, agent });
			await claimDomain(ctx, domain);
			subdomain = "";
			await loaded.run();
		},
		(cause) => errMessage(cause, "Failed to claim domain.")
	);

	const release = createAction(
		async () => {
			const agent = auth.agent;
			const url = apiUrl;
			const domain = loaded.data;
			if (!agent || !url || !domain) return;
			const ctx = createAppviewClient({ apiUrl: url, agent });
			await releaseDomain(ctx, domain);
			await loaded.run();
		},
		(cause) => errMessage(cause, "Failed to release domain.")
	);
	const actionError = $derived(claim.error ?? release.error);

	const releaseDomainClaim = () => {
		const domain = loaded.data;
		if (!auth.agent || release.loading || !domain) return;
		if (!confirm(`Release ${domain}? This removes all site data served from it.`)) return;
		void release.run();
	};
</script>

<SettingsHeader
	title="Sites"
	description="Claim a subdomain to serve static sites built from your repositories."
/>

<div class="flex w-full flex-col gap-4">
	<SettingsToolbar>
		{#snippet start()}
			<DocsButton href="https://docs.tangled.org/sites" />
		{/snippet}
	</SettingsToolbar>

	<ErrorAlert label={loaded.error} />
	{#if actionError}
		<ErrorAlert label={actionError} />
	{/if}

	{#if loaded.loading}
		<!-- stable-height skeleton row so the box doesn't collapse then expand -->
		<SettingsList>
			<div class="flex w-full items-center justify-between gap-4">
				<div class="flex items-center gap-2">
					<Skeleton class="size-4 shrink-0 rounded-full" />
					<Skeleton class="h-4 w-40 rounded-sm" />
				</div>
				<Skeleton class="h-8 w-24 shrink-0 rounded-sm" />
			</div>
		</SettingsList>
	{:else if loaded.data}
		<SettingsList>
			<SettingsEntry icon={Globe} title={loaded.data}>
				{#snippet tags()}
					<Tag color="success" size="sm" icon={Check}>Active</Tag>
				{/snippet}
				{#snippet actions()}
					<Button
						variant="danger"
						icon={Unlink}
						loading={release.loading}
						onclick={releaseDomainClaim}
					>
						Release
					</Button>
				{/snippet}
			</SettingsEntry>
		</SettingsList>
	{:else if loaded.data !== undefined}
		<form class="flex w-full flex-col gap-4" onsubmit={claim.run}>
			<FormRow
				label="Subdomain"
				description="Lowercase letters, digits, and hyphens; 4–63 characters."
			>
				<div class="flex items-center gap-2">
					<Input
						bind:value={subdomain}
						placeholder="floo"
						suffix={sitesDomain ? `.${sitesDomain}` : undefined}
						disabled={claim.loading}
						class="flex-1"
					/>
					<Button
						type="submit"
						variant="primary"
						icon={Plus}
						loading={claim.loading}
						disabled={!subdomain.trim()}
					>
						Claim
					</Button>
				</div>
			</FormRow>
			<SettingsEmpty message="No sites domain claimed yet" />
		</form>
	{/if}
</div>
