<script lang="ts">
	import { Button } from 'bits-ui';
	import { GitBranch, Star, Clock, Import, Search, RefreshCw, LoaderCircle } from '@lucide/svelte';
	import type { Repository } from './types/repo';
	import { createQuery } from '@tanstack/svelte-query';
	import { authClient } from './auth-client';
	import { apiClient } from './api-client';
	import NProgress from 'nprogress';
	import { toast } from 'svelte-sonner';
	import { formatDistanceToNow } from 'date-fns';

	const session = authClient.useSession();

	const query = createQuery(() => ({
		queryKey: ['recent-repositories'],
		queryFn: async () => {
			return await apiClient.request<Repository[]>(`/api/v0/user/repos`);
		},
		enabled: !!$session.data?.user.id,
		staleTime: 30000
	}));

	let searchQuery = $state('');
	let throttledQuery = $state('');

	$effect(() => {
		const value = searchQuery;
		const t = setTimeout(() => {
			throttledQuery = value;
		}, 300);
		return () => clearTimeout(t);
	});

	$effect(() => {
		if (searchResultsQuery.isFetching || query.isFetching) {
			NProgress.start();
		} else {
			NProgress.done();
		}
	});

	const searchResultsQuery = createQuery(() => ({
		queryKey: ['search-repositories', throttledQuery],
		queryFn: async () => {
			return await apiClient.request<Repository[]>(
				`/api/v0/user/repos/search?q=${encodeURIComponent(throttledQuery)}`
			);
		},
		enabled: !!$session.data?.user.id && throttledQuery.length > 0
	}));

	let adding = $state<number | null>(null);
	let added = $state<number[]>([]);
	$effect(() => {
		added = repos.filter((r) => r.added).map((r) => r.id);
	});

	const searching = $derived(throttledQuery.length > 0);
	const repos = $derived(searching ? (searchResultsQuery.data ?? []) : (query.data ?? []));
	const isPending = $derived(searching ? searchResultsQuery.isPending : query.isPending);

	const handleImport = async (repo: Repository) => {
		if (added.includes(repo.id)) {
			toast.warning('Repository already imported');
			return;
		}
		adding = repo.id;
		let response = await fetch('/api/v0/user/repo/add', {
			method: 'POST',
			headers: {
				'Content-Type': 'application/json',
				Authorization: (await apiClient.getToken()) ?? ''
			},
			body: JSON.stringify({
				id: repo.id.toString(),
				name: repo.full_name
			})
		});
		if (!response.ok) {
			toast.warning('Repository already imported');
		} else {
			toast.success('Successfully added repository');
		}
		added.push(repo.id);
		adding = null;
	};

	const languageColors: Record<string, string> = {
		GDScript: 'bg-blue-500',
		'C#': 'bg-green-500',
		Rust: 'bg-orange-500',
		C: 'bg-gray-500',
		'C++': 'bg-pink-500'
	};
</script>

<div class="rounded-xl bg-gray-900 p-6 shadow-xl ring-1 ring-gray-800">
	<div class="mb-6 flex items-center justify-between">
		<div class="flex items-center gap-3">
			<GitBranch class="h-6 w-6 text-gray-400" />
			<h2 class="text-xl font-semibold text-white">Import Git Repository</h2>
			<span class="text-xs text-gray-500">repo must be public</span>
		</div>
		<Button.Root
			class="flex items-center gap-2 rounded-lg px-3 py-2 text-sm text-gray-400 transition-colors hover:bg-gray-800 hover:text-white"
			onclick={() => (searching ? searchResultsQuery.refetch() : query.refetch())}
		>
			<RefreshCw class="h-4 w-4" />
			<span>Refresh</span>
		</Button.Root>
	</div>

	<div class="relative mb-6">
		<Search class="absolute top-1/2 left-3 h-4 w-4 -translate-y-1/2 text-gray-500" />
		<input
			type="text"
			bind:value={searchQuery}
			placeholder="Search repositories..."
			class="w-full rounded-lg border border-gray-700 bg-gray-800 py-2.5 pr-4 pl-10 text-white placeholder-gray-500 transition-colors outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
		/>
	</div>

	<div class="space-y-3">
		{#each repos as repo (repo.id)}
			<div
				class="group flex items-center justify-between rounded-lg border border-gray-800 bg-gray-800/40 p-4 transition-colors hover:border-gray-700 hover:bg-gray-800"
			>
				<div class="flex-1">
					<div class="flex items-center gap-2">
						<h3 class="truncate font-medium text-white">{repo.name}</h3>
					</div>
					{#if repo.description}
						<p class="mt-1 truncate text-sm text-gray-400">{repo.description}</p>
					{:else}
						<p class="mt-1 text-sm text-gray-500 italic">No description</p>
					{/if}
					<div class="mt-2 flex items-center gap-4 text-xs text-gray-500">
						{#if repo.language}
							<span class="flex items-center gap-1.5">
								<span
									class="h-2.5 w-2.5 rounded-full {languageColors[repo.language] ?? 'bg-gray-500'}"
								></span>
								{repo.language}
							</span>
						{/if}
						<span class="flex items-center gap-1">
							<Star class="h-3.5 w-3.5" />
							{repo.stars ?? 0}
						</span>
						<span class="flex items-center gap-1">
							<Clock class="h-3.5 w-3.5" />
							{formatDistanceToNow(new Date(repo.updated_at), { addSuffix: true })}
						</span>
					</div>
				</div>
				<Button.Root
					class="ml-4 flex items-center gap-2 rounded-lg px-4 py-2 text-sm font-medium text-white transition-colors {added.includes(
						repo.id
					)
						? 'border-green-800 bg-green-900'
						: 'bg-blue-600'} disabled:cursor-default disabled:opacity-50"
					disabled={adding !== null}
					onclick={() => handleImport(repo)}
				>
					{#if adding === repo.id}
						<RefreshCw class="h-4 w-4 animate-spin" />
						<span>Adding...</span>
					{:else}
						<Import class="h-4 w-4" />
						<span>{added.includes(repo.id) ? 'Added' : 'Add'}</span>
					{/if}
				</Button.Root>
			</div>
		{:else}
			{#if isPending}
				<div class="flex justify-center">
					<LoaderCircle class="animate-spin" />
				</div>
			{:else}
				<div class="py-8 text-center text-gray-500">
					<p>No repositories found matching "{searchQuery}"</p>
				</div>
			{/if}
		{/each}
	</div>

	<p class="mt-6 text-center text-sm text-gray-500">
		You must have a dist/ folder with index.html + index.wasm
	</p>
</div>
