<script lang="ts">
	import { onMount, getContext } from 'svelte';
	import AppHealthBadge from '$lib/components/app/AppHealthBadge.svelte';
	import AnimatedStatusRing from '$lib/components/app/AnimatedStatusRing.svelte';
	import SparklineChart from '$lib/components/app/SparklineChart.svelte';
	import TagBadge from '$lib/components/app/TagBadge.svelte';
	import { theme } from '$lib/stores/theme.svelte.js';
	import { favorites } from '$lib/stores/favorites.svelte.js';
	import { slide } from 'svelte/transition';

	interface AppLink {
		id: string;
		label: string;
		url: string;
		icon: string | null;
		order: number;
	}

	interface AppTag {
		id: string;
		name: string;
		color: string | null;
	}

	interface AppData {
		id: string;
		name: string;
		url: string;
		icon: string | null;
		iconType: string;
		description: string | null;
		statuses: Array<{ status: string; responseTime: number | null }>;
		links?: AppLink[];
		tags?: AppTag[];
	}

	interface StatusPoint {
		status: string;
		checkedAt: string;
	}

	interface Props {
		app: AppData;
		cardSize?: 'compact' | 'medium' | 'large';
	}

	let { app, cardSize = 'medium' }: Props = $props();

	const cardStyleClass = $derived(`card-${theme.cardStyle}`);

	// Use pre-loaded history from context (set by board page) to avoid N+1 fetches
	const appHistories = getContext<Record<string, { history: StatusPoint[]; uptimePercent: number }> | undefined>('appHistories');
	const preloaded = appHistories?.[app.id];

	let historyData: StatusPoint[] = $state(preloaded?.history ?? []);
	let uptimePercent: number | null = $state(preloaded?.uptimePercent ?? null);
	let historyLoading = $state(!preloaded);
	let linksExpanded = $state(false);
	let showContextMenu = $state(false);
	let contextMenuPos = $state({ x: 0, y: 0 });

	const latestStatus = $derived(app.statuses[0]?.status ?? 'unknown');
	const hasLinks = $derived(Array.isArray(app.links) && app.links.length > 0);
	const hasTags = $derived(Array.isArray(app.tags) && app.tags.length > 0);

	const iconSrc = $derived.by(() => {
		if (!app.icon) return null;

		switch (app.iconType) {
			case 'url':
				return app.icon;
			case 'simple': {
				const slug = app.icon.toLowerCase().replace(/[^a-z0-9]/g, '');
				return `https://cdn.simpleicons.org/${slug}`;
			}
			default:
				return null;
		}
	});

	// Fallback: fetch history only if not pre-loaded via context
	onMount(async () => {
		if (preloaded) return;
		try {
			const res = await fetch(`/api/apps/${app.id}/history`);
			if (res.ok) {
				const json = await res.json();
				if (json.success && json.data) {
					historyData = json.data.history ?? [];
					uptimePercent = json.data.uptimePercent ?? null;
				}
			}
		} catch {
			// Silently fail — sparkline is non-critical
		} finally {
			historyLoading = false;
		}
	});

	function handleContextMenu(e: MouseEvent) {
		e.preventDefault();
		contextMenuPos = { x: e.clientX, y: e.clientY };
		showContextMenu = true;
	}

	function handleWindowClick() {
		showContextMenu = false;
	}

	function toggleFavorite() {
		showContextMenu = false;
		if (favorites.isFavorite(app.id)) {
			favorites.remove(app.id);
		} else {
			favorites.add(app.id);
		}
	}

	function recordClick() {
		fetch('/api/recent-apps', {
			method: 'POST',
			headers: { 'Content-Type': 'application/json' },
			body: JSON.stringify({ appId: app.id })
		}).catch(() => {});
	}

	function toggleLinks(e: MouseEvent) {
		e.preventDefault();
		e.stopPropagation();
		linksExpanded = !linksExpanded;
	}
</script>

<svelte:window onclick={handleWindowClick} />

{#if cardSize === 'compact'}
	<!-- Compact: icon + name only, inline layout -->
	<a
		href={app.url}
		target="_blank"
		rel="noopener noreferrer"
		class="card-hover group flex items-center gap-2 rounded-2xl {cardStyleClass} px-3 py-2 text-left transition-colors hover:border-primary/50"
		data-app-widget
		data-app-url={app.url}
		oncontextmenu={handleContextMenu}
		onclick={recordClick}
	>
		<div class="relative flex-shrink-0">
			<div class="flex h-8 w-8 items-center justify-center rounded-xl bg-muted transition-colors group-hover:bg-accent">
				{#if app.iconType === 'emoji' && app.icon}
					<span class="text-base">{app.icon}</span>
				{:else if iconSrc}
					<img src={iconSrc} alt="{app.name} icon" class="h-5 w-5 object-contain" />
				{:else}
					<span class="text-xs font-bold text-muted-foreground">{app.name.charAt(0).toUpperCase()}</span>
				{/if}
			</div>
			<AnimatedStatusRing status={latestStatus} size={32} animated />
		</div>
		<span class="truncate text-xs font-medium text-foreground transition-colors group-hover:text-primary">
			{app.name}
		</span>
		{#if hasLinks}
			<button
				type="button"
				onclick={toggleLinks}
				class="ml-auto flex-shrink-0 rounded p-0.5 text-muted-foreground hover:text-foreground"
				title="Show links"
			>
				<svg class="h-3 w-3 transition-transform" class:rotate-90={linksExpanded} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
					<polyline points="9 18 15 12 9 6" />
				</svg>
			</button>
		{/if}
	</a>

	<!-- Expanded links for compact -->
	{#if linksExpanded && hasLinks}
		<div transition:slide={{ duration: 200 }} class="ml-10 space-y-0.5 pb-1">
			{#each app.links ?? [] as link (link.id)}
				<a
					href={link.url}
					target="_blank"
					rel="noopener noreferrer"
					class="flex items-center gap-1.5 rounded px-2 py-1 text-[11px] text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
				>
					<svg class="h-3 w-3 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
						<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
						<polyline points="15 3 21 3 21 9" />
						<line x1="10" y1="14" x2="21" y2="3" />
					</svg>
					{link.label}
				</a>
			{/each}
		</div>
	{/if}
{:else if cardSize === 'large'}
	<!-- Large: icon + name + description + sparkline + tags + links -->
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div
		class="card-hover group rounded-[1.4rem] {cardStyleClass} p-5 transition-colors hover:border-primary/50"
		data-app-widget
		data-app-url={app.url}
		oncontextmenu={handleContextMenu}
	>
		<a
			href={app.url}
			target="_blank"
			rel="noopener noreferrer"
			class="flex flex-col items-center gap-3 text-center"
			onclick={recordClick}
		>
			<div class="relative">
				<div class="flex h-16 w-16 items-center justify-center rounded-2xl bg-muted transition-colors group-hover:bg-accent">
					{#if app.iconType === 'emoji' && app.icon}
						<span class="text-3xl">{app.icon}</span>
					{:else if iconSrc}
						<img src={iconSrc} alt="{app.name} icon" class="h-10 w-10 object-contain" />
					{:else}
						<span class="text-xl font-bold text-muted-foreground">{app.name.charAt(0).toUpperCase()}</span>
					{/if}
				</div>
				<AnimatedStatusRing status={latestStatus} size={64} animated />
			</div>

			<span class="w-full truncate text-base font-semibold text-foreground transition-colors group-hover:text-primary">
				{app.name}
			</span>

			{#if app.description}
				<p class="line-clamp-2 w-full text-xs text-muted-foreground">{app.description}</p>
			{/if}

			<AppHealthBadge status={latestStatus} />

			{#if historyLoading}
				<div class="h-5 w-24 animate-pulse rounded bg-muted"></div>
			{:else if historyData.length > 0}
				<div class="flex items-center gap-1">
					<SparklineChart data={historyData} />
					{#if uptimePercent !== null}
						<span class="text-[10px] text-muted-foreground">{uptimePercent}%</span>
					{/if}
				</div>
			{/if}
		</a>

		<!-- Tags -->
		{#if hasTags}
			<div class="mt-2 flex flex-wrap justify-center gap-1">
				{#each app.tags ?? [] as tag (tag.id)}
					<TagBadge name={tag.name} color={tag.color} size="sm" />
				{/each}
			</div>
		{/if}

		<!-- Expandable Links -->
		{#if hasLinks}
			<div class="mt-2 border-t border-border pt-2">
				<button
					type="button"
					onclick={toggleLinks}
					class="flex w-full items-center justify-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground"
				>
					<svg class="h-3 w-3 transition-transform" class:rotate-180={linksExpanded} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
						<polyline points="6 9 12 15 18 9" />
					</svg>
					{linksExpanded ? 'Hide' : `${app.links?.length ?? 0} more`} links
				</button>

				{#if linksExpanded}
					<div transition:slide={{ duration: 200 }} class="mt-1.5 space-y-1">
						{#each app.links ?? [] as link (link.id)}
							<a
								href={link.url}
								target="_blank"
								rel="noopener noreferrer"
								class="flex items-center gap-2 rounded-md px-2 py-1.5 text-xs text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
							>
								<svg class="h-3.5 w-3.5 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
									<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
									<polyline points="15 3 21 3 21 9" />
									<line x1="10" y1="14" x2="21" y2="3" />
								</svg>
								{link.label}
							</a>
						{/each}
					</div>
				{/if}
			</div>
		{/if}
	</div>
{:else}
	<!-- Medium (default): icon + name + status + sparkline on hover + links -->
	<!-- svelte-ignore a11y_no_static_element_interactions -->
	<div
		class="card-hover group rounded-[1.4rem] {cardStyleClass} p-4 transition-colors hover:border-primary/50"
		data-app-widget
		data-app-url={app.url}
		oncontextmenu={handleContextMenu}
	>
		<a
			href={app.url}
			target="_blank"
			rel="noopener noreferrer"
			class="flex flex-col items-center gap-2 text-center"
			onclick={recordClick}
		>
			<div class="relative">
				<div class="flex h-12 w-12 items-center justify-center rounded-2xl bg-muted transition-colors group-hover:bg-accent">
					{#if app.iconType === 'emoji' && app.icon}
						<span class="text-2xl">{app.icon}</span>
					{:else if iconSrc}
						<img src={iconSrc} alt="{app.name} icon" class="h-8 w-8 object-contain" />
					{:else}
						<span class="text-lg font-bold text-muted-foreground">{app.name.charAt(0).toUpperCase()}</span>
					{/if}
				</div>
				<AnimatedStatusRing status={latestStatus} size={48} animated />
			</div>

			<span class="w-full truncate text-sm font-medium text-foreground transition-colors group-hover:text-primary">
				{app.name}
			</span>

			<AppHealthBadge status={latestStatus} />

			{#if historyLoading}
				<div class="h-5 w-20 animate-pulse rounded bg-muted"></div>
			{:else if historyData.length > 0}
				<div class="flex items-center gap-1">
					<SparklineChart data={historyData} />
					{#if uptimePercent !== null}
						<span class="text-[10px] text-muted-foreground">{uptimePercent}%</span>
					{/if}
				</div>
			{/if}
		</a>

		<!-- Expandable Links -->
		{#if hasLinks}
			<div class="mt-2 border-t border-border pt-2">
				<button
					type="button"
					onclick={toggleLinks}
					class="flex w-full items-center justify-center gap-1 text-xs text-muted-foreground transition-colors hover:text-foreground"
				>
					<svg class="h-3 w-3 transition-transform" class:rotate-180={linksExpanded} viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
						<polyline points="6 9 12 15 18 9" />
					</svg>
					{linksExpanded ? 'Hide' : `${app.links?.length ?? 0} more`}
				</button>

				{#if linksExpanded}
					<div transition:slide={{ duration: 200 }} class="mt-1 space-y-0.5">
						{#each app.links ?? [] as link (link.id)}
							<a
								href={link.url}
								target="_blank"
								rel="noopener noreferrer"
								class="flex items-center gap-1.5 rounded px-2 py-1 text-[11px] text-muted-foreground transition-colors hover:bg-accent hover:text-foreground"
							>
								<svg class="h-3 w-3 flex-shrink-0" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
									<path d="M18 13v6a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V8a2 2 0 0 1 2-2h6" />
									<polyline points="15 3 21 3 21 9" />
									<line x1="10" y1="14" x2="21" y2="3" />
								</svg>
								{link.label}
							</a>
						{/each}
					</div>
				{/if}
			</div>
		{/if}
	</div>
{/if}

<!-- Context Menu -->
{#if showContextMenu}
	<div
		class="fixed z-50 rounded-2xl border border-border bg-popover p-1 shadow-[var(--shadow-soft)]"
		style="left: {contextMenuPos.x}px; top: {contextMenuPos.y}px"
	>
		<button
			type="button"
			class="flex w-full items-center gap-2 rounded-xl px-3 py-2 text-sm text-popover-foreground transition-colors hover:bg-accent"
			onclick={toggleFavorite}
		>
			{#if favorites.isFavorite(app.id)}
				<svg class="h-4 w-4" viewBox="0 0 24 24" fill="currentColor" stroke="currentColor" stroke-width="2">
					<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
				</svg>
				Remove from favorites
			{:else}
				<svg class="h-4 w-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2">
					<polygon points="12 2 15.09 8.26 22 9.27 17 14.14 18.18 21.02 12 17.77 5.82 21.02 7 14.14 2 9.27 8.91 8.26 12 2" />
				</svg>
				Add to favorites
			{/if}
		</button>
	</div>
{/if}
