<script lang="ts">
	import type { Component } from "svelte";
	import type { SvelteHTMLElements } from "svelte/elements";
	import { page } from "$app/state";
	import { getAuth } from "$lib/auth.svelte";
	import { createAppviewClient } from "$lib/api/appview";
	import {
		getNotificationPreferences,
		updateNotificationPreferences,
		type NotificationPreferences
	} from "$lib/api/notifications";
	import Button from "$lib/components/ui/Button.svelte";
	import Toggle from "$lib/components/ui/Toggle.svelte";
	import Skeleton from "$lib/components/ui/Skeleton.svelte";
	import ErrorAlert from "$lib/components/ui/Error.svelte";
	import SettingsHeader from "../SettingsHeader.svelte";
	import SettingsList from "../SettingsList.svelte";
	import { createAction, createLoad } from "$lib/action.svelte";
	import Save from "$icon/save";
	import Star from "$icon/star";
	import CircleDot from "$icon/circle-dot";
	import MessageSquare from "$icon/message-square";
	import CircleSlash from "$icon/circle-slash";
	import GitPullRequest from "$icon/git-pull-request";
	import GitMerge from "$icon/git-merge";
	import UserRound from "$icon/user-round";
	import AtSign from "$icon/at-sign";
	import Mail from "$icon/mail";

	type PrefKey = keyof NotificationPreferences;

	interface Pref {
		key: PrefKey;
		icon: Component<SvelteHTMLElements["svg"]>;
		label: string;
		description: string;
		enabled: boolean;
	}

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

	// row definitions map the design-system UI onto the api's preference keys.
	let prefs = $state<Pref[]>([
		{
			key: "repoStarred",
			icon: Star,
			label: "Repository starred",
			description: "When someone stars your repository.",
			enabled: false
		},
		{
			key: "issueCreated",
			icon: CircleDot,
			label: "New issues",
			description: "When someone creates an issue on your repository.",
			enabled: false
		},
		{
			key: "issueCommented",
			icon: MessageSquare,
			label: "Issue comments",
			description: "When someone comments on an issue you're involved with.",
			enabled: false
		},
		{
			key: "issueClosed",
			icon: CircleSlash,
			label: "Issue closed",
			description: "When an issue on your repository is closed.",
			enabled: false
		},
		{
			key: "pullCreated",
			icon: GitPullRequest,
			label: "New pull requests",
			description: "When someone creates a pull request on your repository.",
			enabled: false
		},
		{
			key: "pullCommented",
			icon: MessageSquare,
			label: "Pull request comments",
			description: "When someone comments on a pull request you're involved with.",
			enabled: false
		},
		{
			key: "pullMerged",
			icon: GitMerge,
			label: "Pull request merged",
			description: "When your pull request is merged.",
			enabled: false
		},
		{
			key: "followed",
			icon: UserRound,
			label: "New followers",
			description: "When someone follows you.",
			enabled: false
		},
		{
			key: "userMentioned",
			icon: AtSign,
			label: "Mentions",
			description: "When someone mentions you.",
			enabled: false
		},
		{
			key: "emailNotifications",
			icon: Mail,
			label: "Email notifications",
			description: "Receive digest emails for issue and pull request activity.",
			enabled: false
		}
	]);

	// last-saved values; Save lights up when the toggles drift from these.
	let baseline = $state<NotificationPreferences | null>(null);

	const dirty = $derived(baseline !== null && prefs.some((p) => p.enabled !== baseline![p.key]));

	const loaded = createLoad(async () => {
		const agent = auth.agent;
		const url = apiUrl;
		if (!agent || !url) return;
		const ctx = createAppviewClient({ apiUrl: url, agent });
		const values = await getNotificationPreferences(ctx);
		for (const pref of prefs) pref.enabled = values[pref.key];
		baseline = values;
	});

	const save = createAction(async () => {
		const agent = auth.agent;
		const url = apiUrl;
		if (!agent || !url || !baseline || !dirty) return;
		// send only the toggles that changed since the last save.
		const patch: Partial<NotificationPreferences> = {};
		for (const pref of prefs) {
			if (pref.enabled !== baseline[pref.key]) patch[pref.key] = pref.enabled;
		}
		const ctx = createAppviewClient({ apiUrl: url, agent });
		await updateNotificationPreferences(ctx, patch);
		baseline = { ...baseline, ...patch };
	});
</script>

<SettingsHeader
	title="Notifications"
	description="Choose which notifications you want to receive when activity happens on your repositories and profile."
>
	{#snippet action()}
		<Button variant="primary" icon={Save} disabled={!dirty || save.loading} onclick={save.run}>
			Save
		</Button>
	{/snippet}
</SettingsHeader>

<ErrorAlert label={loaded.error} />
<ErrorAlert label={save.error} />

<!-- the full list renders immediately (even server-side) so the layout is
	stable; only the toggle values fill in once loaded, swapping a same-size
	skeleton for the real control to avoid a spinner and any bounding-box shift. -->
<SettingsList>
	{#each prefs as pref (pref.key)}
		{@const Glyph = pref.icon}
		<div class="flex w-full items-center justify-between gap-4">
			<div class="flex min-w-0 flex-col gap-1">
				<span class="flex items-center gap-2">
					<Glyph class="size-3.5 shrink-0 text-foreground-default" aria-hidden="true" />
					<span class="typography-paragraph-regular text-foreground-default">{pref.label}</span>
				</span>
				<span class="typography-paragraph-regular text-foreground-muted">{pref.description}</span>
			</div>
			{#if loaded.loading}
				<Skeleton class="h-4.5 w-8.25 shrink-0 rounded-full" />
			{:else}
				<Toggle bind:checked={pref.enabled} disabled={save.loading} aria-label={pref.label} />
			{/if}
		</div>
	{/each}
</SettingsList>
