<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 Spinner from "$lib/components/ui/Spinner.svelte";
	import ErrorAlert from "$lib/components/ui/Error.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 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 domain = $state<string | null>(null);
	let loading = $state(true);
	let loadError = $state<string | null>(null);
	let actionError = $state<string | null>(null);
	let subdomain = $state("");
	let claiming = $state(false);
	let releasing = $state(false);

	// 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 load = async () => {
		const agent = auth.agent;
		if (!agent || !apiUrl) return;
		loading = true;
		loadError = null;
		try {
			const ctx = createAppviewClient({ apiUrl, agent });
			domain = await getDomainClaim(ctx);
		} catch (err) {
			loadError = errMessage(err, "Failed to load your sites domain.");
		} finally {
			loading = false;
		}
	};

	$effect(() => {
		if (auth.agent && apiUrl) void load();
	});

	const claim = async () => {
		const agent = auth.agent;
		const sd = subdomain.trim();
		if (!agent || !apiUrl || !sd || claiming) return;
		claiming = true;
		actionError = null;
		try {
			const ctx = createAppviewClient({ apiUrl, agent });
			await claimDomain(ctx, sd);
			subdomain = "";
			await load();
		} catch (err) {
			actionError = errMessage(err, "Failed to claim domain.");
		} finally {
			claiming = false;
		}
	};

	const release = async () => {
		const agent = auth.agent;
		if (!agent || !apiUrl || !domain || releasing) return;
		if (!confirm(`Release ${domain}? This removes all site data served from it.`)) return;
		releasing = true;
		actionError = null;
		try {
			const ctx = createAppviewClient({ apiUrl, agent });
			await releaseDomain(ctx, domain);
			await load();
		} catch (err) {
			actionError = errMessage(err, "Failed to release domain.");
		} finally {
			releasing = false;
		}
	};
</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>

	{#if loadError}
		<ErrorAlert label={loadError} />
	{/if}
	{#if actionError}
		<ErrorAlert label={actionError} />
	{/if}

	{#if loading}
		<div class="flex items-center justify-center gap-2 p-4 text-sm text-foreground-subtle">
			<Spinner /> Loading…
		</div>
	{:else if domain}
		<SettingsList>
			<SettingsEntry icon={Globe} title={domain}>
				{#snippet tags()}
					<Tag color="success" size="sm" icon={Check}>Active</Tag>
				{/snippet}
				{#snippet actions()}
					<Button variant="danger" icon={Unlink} disabled={releasing} onclick={release}>
						Release
					</Button>
				{/snippet}
			</SettingsEntry>
		</SettingsList>
	{:else}
		<form
			class="flex w-full flex-col gap-4"
			onsubmit={(e) => {
				e.preventDefault();
				void claim();
			}}
		>
			<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={claiming}
						class="flex-1"
					/>
					<Button type="submit" variant="primary" icon={Plus} disabled={claiming || !subdomain.trim()}>
						Claim
					</Button>
				</div>
			</FormRow>
			<SettingsEmpty message="No sites domain claimed yet" />
		</form>
	{/if}
</div>
