<script lang="ts">
	import { untrack } from "svelte";
	import {
		Avatar,
		Button,
		Spinner,
		EmptyState,
		Input,
	} from "$lib/components/ui";
	import * as m from "$lib/paraglide/messages";
	import type { SupabaseClient } from "@supabase/supabase-js";
	import type { Database } from "$lib/supabase/types";

	interface ActivityEntry {
		id: string;
		action: string;
		entity_type: string;
		entity_id: string | null;
		entity_name: string | null;
		created_at: string | null;
		metadata: Record<string, unknown> | null;
		profiles: {
			full_name: string | null;
			email: string | null;
			avatar_url: string | null;
		} | null;
	}

	interface Props {
		supabase: SupabaseClient<Database>;
		orgId: string;
	}

	let { supabase, orgId }: Props = $props();

	const PAGE_SIZE = 50;

	let entries = $state<ActivityEntry[]>([]);
	let isLoading = $state(false);
	let isLoadingMore = $state(false);
	let hasMore = $state(true);
	let totalCount = $state<number | null>(null);
	let activeFilter = $state<string>("all");
	let searchQuery = $state("");
	let initialLoaded = $state(false);

	const filters: { id: string; label: () => string; icon: string }[] = [
		{ id: "all", label: m.settings_activity_filter_all, icon: "list" },
		{
			id: "create",
			label: m.settings_activity_filter_create,
			icon: "add_circle",
		},
		{
			id: "update",
			label: m.settings_activity_filter_update,
			icon: "edit",
		},
		{
			id: "delete",
			label: m.settings_activity_filter_delete,
			icon: "delete",
		},
		{
			id: "move",
			label: m.settings_activity_filter_move,
			icon: "drive_file_move",
		},
		{
			id: "rename",
			label: m.settings_activity_filter_rename,
			icon: "edit_note",
		},
	];

	const filteredEntries = $derived(
		searchQuery.trim()
			? entries.filter((e) => {
					const q = searchQuery.toLowerCase();
					const name = (e.entity_name ?? "").toLowerCase();
					const user = (
						e.profiles?.full_name ??
						e.profiles?.email ??
						""
					).toLowerCase();
					const entityType = e.entity_type.toLowerCase();
					return (
						name.includes(q) ||
						user.includes(q) ||
						entityType.includes(q)
					);
				})
			: entries,
	);

	async function loadEntries(reset = false) {
		if (reset) {
			entries = [];
			hasMore = true;
			isLoading = true;
		} else {
			isLoadingMore = true;
		}

		let query = supabase
			.from("activity_log")
			.select(
				`id, action, entity_type, entity_id, entity_name, created_at, metadata,
				profiles:user_id ( full_name, email, avatar_url )`,
				{ count: "exact" },
			)
			.eq("org_id", orgId)
			.order("created_at", { ascending: false })
			.range(entries.length, entries.length + PAGE_SIZE - 1);

		if (activeFilter !== "all") {
			query = query.eq("action", activeFilter);
		}

		const { data, count, error } = await query;

		if (!error && data) {
			if (reset) {
				entries = data as unknown as ActivityEntry[];
			} else {
				entries = [...entries, ...(data as unknown as ActivityEntry[])];
			}
			totalCount = count;
			hasMore = data.length === PAGE_SIZE;
		}

		isLoading = false;
		isLoadingMore = false;
		initialLoaded = true;
	}

	$effect(() => {
		// Re-load when filter changes — only track activeFilter, not internal state
		const _filter = activeFilter;
		untrack(() => loadEntries(true));
	});

	function getEntityTypeLabel(entityType: string): string {
		const map: Record<string, () => string> = {
			document: m.entity_document,
			folder: m.entity_folder,
			kanban_board: m.entity_kanban_board,
			kanban_card: m.entity_kanban_card,
			kanban_column: m.entity_kanban_column,
			member: m.entity_member,
			role: m.entity_role,
			invite: m.entity_invite,
			event: m.entity_event,
		};
		return (map[entityType] ?? (() => entityType))();
	}

	function getActivityIcon(action: string): string {
		const map: Record<string, string> = {
			create: "add_circle",
			update: "edit",
			delete: "delete",
			move: "drive_file_move",
			rename: "edit_note",
		};
		return map[action] ?? "info";
	}

	function getActivityColor(action: string): string {
		const map: Record<string, string> = {
			create: "text-emerald-400",
			update: "text-blue-400",
			delete: "text-red-400",
			move: "text-amber-400",
			rename: "text-purple-400",
		};
		return map[action] ?? "text-light/50";
	}

	function getActivityBg(action: string): string {
		const map: Record<string, string> = {
			create: "bg-emerald-400/10",
			update: "bg-blue-400/10",
			delete: "bg-red-400/10",
			move: "bg-amber-400/10",
			rename: "bg-purple-400/10",
		};
		return map[action] ?? "bg-light/5";
	}

	function getDescription(entry: ActivityEntry): string {
		const userName =
			entry.profiles?.full_name || entry.profiles?.email || "Someone";
		const entityType = getEntityTypeLabel(entry.entity_type);
		const name = entry.entity_name ?? "-";

		const map: Record<string, () => string> = {
			create: () =>
				m.activity_created({ user: userName, entityType, name }),
			update: () =>
				m.activity_updated({ user: userName, entityType, name }),
			delete: () =>
				m.activity_deleted({ user: userName, entityType, name }),
			move: () => m.activity_moved({ user: userName, entityType, name }),
			rename: () =>
				m.activity_renamed({ user: userName, entityType, name }),
		};
		return (map[entry.action] ?? map["update"]!)();
	}

	function formatFullDate(dateStr: string | null): string {
		if (!dateStr) return "";
		const d = new Date(dateStr);
		return d.toLocaleDateString(undefined, {
			year: "numeric",
			month: "short",
			day: "numeric",
			hour: "2-digit",
			minute: "2-digit",
		});
	}

	function formatRelativeDate(dateStr: string | null): string {
		if (!dateStr) return "";
		const now = Date.now();
		const then = new Date(dateStr).getTime();
		const diffMs = now - then;
		const diffMin = Math.floor(diffMs / 60000);
		if (diffMin < 1) return m.activity_just_now();
		if (diffMin < 60)
			return m.activity_minutes_ago({ count: String(diffMin) });
		const diffHr = Math.floor(diffMin / 60);
		if (diffHr < 24) return m.activity_hours_ago({ count: String(diffHr) });
		const diffDay = Math.floor(diffHr / 24);
		return m.activity_days_ago({ count: String(diffDay) });
	}

	function getDateGroup(dateStr: string | null): string {
		if (!dateStr) return "";
		const d = new Date(dateStr);
		const now = new Date();
		const today = new Date(
			now.getFullYear(),
			now.getMonth(),
			now.getDate(),
		);
		const entryDate = new Date(d.getFullYear(), d.getMonth(), d.getDate());
		const diffDays = Math.floor(
			(today.getTime() - entryDate.getTime()) / 86400000,
		);

		if (diffDays === 0) return "Today";
		if (diffDays === 1) return "Yesterday";
		if (diffDays < 7) return `${diffDays} days ago`;
		return d.toLocaleDateString(undefined, {
			year: "numeric",
			month: "long",
			day: "numeric",
		});
	}

	// Group entries by date
	const groupedEntries = $derived(() => {
		const groups: { label: string; entries: ActivityEntry[] }[] = [];
		let currentLabel = "";
		for (const entry of filteredEntries) {
			const label = getDateGroup(entry.created_at);
			if (label !== currentLabel) {
				currentLabel = label;
				groups.push({ label, entries: [] });
			}
			groups[groups.length - 1].entries.push(entry);
		}
		return groups;
	});
</script>

<div class="space-y-4">
	<!-- Header -->
	<div
		class="flex flex-col sm:flex-row sm:items-center justify-between gap-3"
	>
		<div>
			<h2 class="text-body font-heading text-white">
				{m.settings_activity_title()}
			</h2>
			<p class="text-body-sm text-light/50 mt-0.5">
				{m.settings_activity_desc()}
			</p>
		</div>
		{#if totalCount !== null}
			<span
				class="text-[11px] text-light/30 bg-dark/50 px-3 py-1.5 rounded-lg shrink-0"
			>
				{m.settings_activity_count({ count: String(totalCount) })}
			</span>
		{/if}
	</div>

	<!-- Filters + Search -->
	<div class="flex flex-col sm:flex-row gap-3">
		<div class="flex flex-wrap gap-1.5">
			{#each filters as filter}
				<button
					type="button"
					class="flex items-center gap-1.5 px-2.5 py-1.5 rounded-lg text-[12px] font-body transition-colors {activeFilter ===
					filter.id
						? 'bg-primary text-background'
						: 'text-light/50 hover:text-white hover:bg-dark/50 bg-dark/20'}"
					onclick={() => (activeFilter = filter.id)}
				>
					<span
						class="material-symbols-rounded"
						style="font-size: 14px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 14;"
						>{filter.icon}</span
					>
					{filter.label()}
				</button>
			{/each}
		</div>
		<div class="sm:ml-auto w-full sm:w-64">
			<Input
				placeholder={m.settings_activity_search_placeholder()}
				bind:value={searchQuery}
				icon="search"
			/>
		</div>
	</div>

	<!-- Content -->
	{#if isLoading}
		<div class="flex items-center justify-center py-16">
			<Spinner size="lg" />
		</div>
	{:else if filteredEntries.length === 0 && initialLoaded}
		<div class="bg-dark/30 border border-light/5 rounded-xl p-8">
			<EmptyState
				title={m.settings_activity_empty()}
				description={searchQuery
					? "Try a different search term."
					: m.settings_activity_desc()}
			/>
		</div>
	{:else}
		<div class="flex flex-col gap-1">
			{#each groupedEntries() as group}
				<!-- Date group header -->
				<div
					class="sticky top-0 z-10 bg-background/80 backdrop-blur-sm px-1 py-2 mt-2 first:mt-0"
				>
					<span
						class="text-[11px] font-heading text-light/30 uppercase tracking-wider"
					>
						{group.label}
					</span>
				</div>

				{#each group.entries as entry (entry.id)}
					<div
						class="flex items-start gap-3 px-3 py-3 rounded-xl hover:bg-dark/30 transition-colors group"
					>
						<!-- Icon -->
						<div
							class="w-8 h-8 rounded-lg {getActivityBg(
								entry.action,
							)} flex items-center justify-center shrink-0 mt-0.5"
						>
							<span
								class="material-symbols-rounded {getActivityColor(
									entry.action,
								)}"
								style="font-size: 16px; font-variation-settings: 'FILL' 0, 'wght' 400, 'GRAD' 0, 'opsz' 16;"
								>{getActivityIcon(entry.action)}</span
							>
						</div>

						<!-- Content -->
						<div class="flex-1 min-w-0">
							<p
								class="text-body-sm text-light/80 leading-relaxed"
							>
								{getDescription(entry)}
							</p>
							<div class="flex items-center gap-3 mt-1">
								{#if entry.profiles}
									<div class="flex items-center gap-1.5">
										<Avatar
											name={entry.profiles.full_name ??
												entry.profiles.email ??
												"?"}
											src={entry.profiles.avatar_url}
											size="xs"
										/>
										<span class="text-[11px] text-light/40">
											{entry.profiles.full_name ??
												entry.profiles.email}
										</span>
									</div>
								{/if}
								<span class="text-[11px] text-light/20">·</span>
								<span
									class="text-[11px] text-light/30"
									title={formatFullDate(entry.created_at)}
								>
									{formatRelativeDate(entry.created_at)}
								</span>
								<span
									class="text-[11px] text-light/20 hidden group-hover:inline"
								>
									{formatFullDate(entry.created_at)}
								</span>
							</div>
						</div>

						<!-- Entity type badge -->
						<span
							class="text-[10px] text-light/30 bg-dark/50 px-2 py-1 rounded-md shrink-0 mt-1"
						>
							{getEntityTypeLabel(entry.entity_type)}
						</span>
					</div>
				{/each}
			{/each}
		</div>

		<!-- Load more / End -->
		<div class="flex justify-center py-4">
			{#if isLoadingMore}
				<Spinner />
			{:else if hasMore}
				<Button
					variant="tertiary"
					size="sm"
					icon="expand_more"
					onclick={() => loadEntries(false)}
				>
					{m.settings_activity_load_more()}
				</Button>
			{:else if entries.length > 0}
				<p class="text-[11px] text-light/20">
					{m.settings_activity_end()}
				</p>
			{/if}
		</div>
	{/if}
</div>
