<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 Spinner from "$lib/components/ui/Spinner.svelte";
	import ErrorAlert from "$lib/components/ui/Error.svelte";
	import SettingsHeader from "../SettingsHeader.svelte";
	import SettingsList from "../SettingsList.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
		}
	]);

	let loading = $state(true);
	let saving = $state(false);
	let loadError = $state<string | null>(null);
	let saveError = $state<string | null>(null);
	// 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 load = async () => {
		const agent = auth.agent;
		if (!agent || !apiUrl) return;
		loading = true;
		loadError = null;
		try {
			const ctx = createAppviewClient({ apiUrl, agent });
			const values = await getNotificationPreferences(ctx);
			for (const pref of prefs) pref.enabled = values[pref.key];
			baseline = values;
		} catch (err) {
			loadError =
				err instanceof Error ? err.message : "Failed to load notification preferences.";
		} finally {
			loading = false;
		}
	};

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

	const save = async () => {
		const agent = auth.agent;
		if (!agent || !apiUrl || !baseline || !dirty) return;
		saving = true;
		saveError = null;
		// 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;
		}
		try {
			const ctx = createAppviewClient({ apiUrl, agent });
			await updateNotificationPreferences(ctx, patch);
			baseline = { ...baseline, ...patch };
		} catch (err) {
			saveError = err instanceof Error ? err.message : "Failed to save preferences.";
		} finally {
			saving = false;
		}
	};
</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 || saving} onclick={save}>Save</Button>
	{/snippet}
</SettingsHeader>

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

{#if loading}
	<div class="flex items-center justify-center gap-2 p-4 text-sm text-foreground-subtle">
		<Spinner /> Loading…
	</div>
{:else}
	<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>
				<Toggle bind:checked={pref.enabled} disabled={saving} aria-label={pref.label} />
			</div>
		{/each}
	</SettingsList>
{/if}
