<script lang="ts">
	import { onMount } from 'svelte';
	import { client } from '$lib/graphql/client';
	import { JobsDocument, type JobsQuery } from '$lib/graphql/__generated__/graphql';
	import JobsTable from './JobsTable.svelte';
	import JobFilters from './JobFilters.svelte';
	import { Button } from '$lib/components/ui/button';
	import { Card, CardContent, CardHeader, CardTitle } from '$lib/components/ui/card';
	import {
		type JobFilters as JobFiltersType,
		parseJobFiltersFromURL,
		syncJobFiltersToURL,
		jobFiltersToGraphQLWhere,
		jobSortToGraphQLOrder,
		hasActiveJobFilters,
		EMPTY_JOB_FILTERS,
	} from '$lib/utils/jobFilterParams';

	const PAGE_SIZE = 20;

	type JobsConnection = NonNullable<JobsQuery['jobs']>;
	type JobEdge = NonNullable<JobsConnection['edges']>[number];
	type PageInfo = JobsConnection['pageInfo'];

	let edges: JobEdge[] = $state([]);
	let pageInfo: PageInfo | null = $state(null);
	let fetching = $state(false);
	let error: string | null = $state(null);
	let initialLoad = $state(true);
	let filters: JobFiltersType = $state({ ...EMPTY_JOB_FILTERS });

	// Pagination: stack of "after" cursors used to reach each page
	// cursorStack[0] = the "after" cursor used to fetch page 2, etc.
	let cursorStack: (string | null)[] = $state([]);
	let currentPage = $derived(cursorStack.length + 1);

	const jobs = $derived((edges ?? []).map((edge) => edge.node).filter(Boolean));

	// Extract unique job types from loaded data for the filter dropdown
	const availableJobTypes = $derived(
		[...new Set(jobs.map((job) => job.jobType))].sort()
	);

	async function fetchJobs(after: string | null = null) {
		fetching = true;
		error = null;

		try {
			const where = jobFiltersToGraphQLWhere(filters);
			const order = jobSortToGraphQLOrder(filters.sort);
			const result = await client
				.query(JobsDocument, { first: PAGE_SIZE, after, where, order }, { requestPolicy: 'network-only' })
				.toPromise();

			if (result.error) {
				error = result.error.message;
				return;
			}

			if (result.data?.jobs) {
				edges = result.data.jobs.edges ?? [];
				pageInfo = result.data.jobs.pageInfo;
			}
		} catch (e) {
			error = e instanceof Error ? e.message : 'Unknown error';
		} finally {
			fetching = false;
			initialLoad = false;
		}
	}

	function nextPage() {
		if (pageInfo?.endCursor && pageInfo.hasNextPage) {
			cursorStack = [...cursorStack, pageInfo.endCursor];
			fetchJobs(pageInfo.endCursor);
		}
	}

	function prevPage() {
		if (cursorStack.length > 0) {
			const newStack = [...cursorStack];
			newStack.pop(); // remove current page's cursor
			cursorStack = newStack;
			// Fetch with the previous page's cursor (or null for page 1)
			const after = newStack.length > 0 ? newStack[newStack.length - 1] : null;
			fetchJobs(after);
		}
	}

	function handleFilterChange(newFilters: JobFiltersType) {
		filters = newFilters;
		edges = [];
		pageInfo = null;
		cursorStack = [];
		syncJobFiltersToURL(filters);
		fetchJobs();
	}

	onMount(() => {
		filters = parseJobFiltersFromURL();
		fetchJobs();

		const handlePopState = () => {
			filters = parseJobFiltersFromURL();
			edges = [];
			pageInfo = null;
			cursorStack = [];
			fetchJobs();
		};

		window.addEventListener('popstate', handlePopState);
		return () => window.removeEventListener('popstate', handlePopState);
	});
</script>

<div class="space-y-4">
	<Card class="shadow-md shadow-primary/10">
		<CardHeader>
			<CardTitle>Filters</CardTitle>
		</CardHeader>
		<CardContent>
			<JobFilters {filters} onFilterChange={handleFilterChange} availableJobTypes={availableJobTypes} />
		</CardContent>
	</Card>

	{#if fetching && initialLoad}
		<Card>
			<CardContent>
				<div class="flex items-center justify-center py-8">
					<div
						class="border-primary h-10 w-10 animate-spin rounded-full border-2 border-t-transparent"
						aria-label="Loading jobs"
					></div>
				</div>
			</CardContent>
		</Card>
	{/if}

	{#if error}
		<Card class="border-destructive/40 bg-destructive/5">
			<CardContent>
				<p class="text-destructive py-4 text-sm">Could not load jobs: {error}</p>
			</CardContent>
		</Card>
	{/if}

	{#if !initialLoad && !error && jobs.length === 0}
		<Card>
			<CardContent>
				<p class="text-muted-foreground py-4 text-sm">
					{#if hasActiveJobFilters(filters)}
						No jobs match your filters. Try adjusting your search criteria.
					{:else}
						No jobs found.
					{/if}
				</p>
			</CardContent>
		</Card>
	{/if}

	{#if jobs.length > 0}
		<JobsTable {jobs} />

		<!-- Pagination -->
		<div class="flex items-center justify-center gap-4">
			<Button variant="outline" size="sm" disabled={currentPage === 1 || fetching} onclick={prevPage}>
				Previous
			</Button>
			<span class="text-sm text-muted-foreground">Page {currentPage}</span>
			<Button variant="outline" size="sm" disabled={!pageInfo?.hasNextPage || fetching} onclick={nextPage}>
				Next
			</Button>
		</div>
	{/if}
</div>
