<script lang="ts" generics="TData, TValue">
	import { onMount } from 'svelte';
	import {
		type ColumnDef,
		getCoreRowModel
	} from "@tanstack/table-core";
	import { createSvelteTable, FlexRender } from "$lib/components/ui/data-table/index.js";
	import * as Table from "$lib/components/ui/table/index.js";

	type DataTableProps<TData, TValue> = {
		columns: ColumnDef<TData, TValue>[];
		data: TData[];
		loading: boolean;
		hasMore: boolean;
		loadMore: () => void;
		onRowClick?: (row: TData) => void;
		selectedId?: number | null;
	};

	let {
		data,
		columns,
		loading,
		hasMore,
		loadMore,
		onRowClick,
		selectedId = null
	}: DataTableProps<TData, TValue> = $props();

	const table = createSvelteTable({
		get data() {
			return data;
		},
		columns,
		getCoreRowModel: getCoreRowModel()
	});

	let scrollContainer = $state<HTMLDivElement>();
	let loadingTrigger = $state<HTMLDivElement>();
	let tableContainer = $state<HTMLDivElement>();
	let bottomScrollbar = $state<HTMLDivElement>();
	let bottomScrollbarInner = $state<HTMLDivElement>();
	let isSyncingHorizontalScroll = false;

	// Intersection Observer para detectar cuando el usuario llega al final
	$effect(() => {
		const target = loadingTrigger;
		const root = scrollContainer;
		if (!target) return;

		const observer = new IntersectionObserver(
			(entries) => {
				const [entry] = entries;
				if (entry.isIntersecting && hasMore && !loading) {
					loadMore();
				}
			},
			{
				root: root,
				threshold: 0.1
			}
		);

		observer.observe(target);

		return () => {
			observer.disconnect();
		};
	});

	function syncBottomScrollbarWidth() {
		if (!tableContainer || !bottomScrollbarInner) return;
		const width = Math.max(tableContainer.scrollWidth || 0, tableContainer.clientWidth + 1);
		bottomScrollbarInner.style.width = `${width}px`;
	}

	function handleTableHorizontalScroll() {
		if (!tableContainer || !bottomScrollbar || isSyncingHorizontalScroll) return;
		isSyncingHorizontalScroll = true;
		bottomScrollbar.scrollLeft = tableContainer.scrollLeft;
		isSyncingHorizontalScroll = false;
	}

	function handleBottomHorizontalScroll() {
		if (!tableContainer || !bottomScrollbar || isSyncingHorizontalScroll) return;
		isSyncingHorizontalScroll = true;
		tableContainer.scrollLeft = bottomScrollbar.scrollLeft;
		isSyncingHorizontalScroll = false;
	}

	onMount(() => {
		tableContainer = scrollContainer?.querySelector('[data-slot="table-container"]') ?? undefined;
		if (!tableContainer) return;

		const resizeObserver = new ResizeObserver(() => {
			syncBottomScrollbarWidth();
		});

		tableContainer.addEventListener('scroll', handleTableHorizontalScroll, { passive: true });
		resizeObserver.observe(tableContainer);
		const tableEl = tableContainer.querySelector('[data-slot="table"]');
		if (tableEl) resizeObserver.observe(tableEl);

		syncBottomScrollbarWidth();

		return () => {
			tableContainer?.removeEventListener('scroll', handleTableHorizontalScroll);
			resizeObserver.disconnect();
		};
	});

	$effect(() => {
		data;
		columns;
		queueMicrotask(() => syncBottomScrollbarWidth());
	});
</script>

<div class="w-full">
	<div
		class="catalog-table-shell min-h-[400px] max-h-[calc(100vh-310px)] overflow-y-auto [&_[data-slot=table-container]]:w-full [&_[data-slot=table-container]]:overflow-x-auto"
		bind:this={scrollContainer}
	>
		<Table.Root class="w-max min-w-[1500px]">
			<Table.Header class="catalog-table-header">
				{#each table.getHeaderGroups() as headerGroup (headerGroup.id)}
					<Table.Row>
						{#each headerGroup.headers as header (header.id)}
							<Table.Head class="whitespace-nowrap">
								{#if !header.isPlaceholder}
									<FlexRender
										content={header.column.columnDef.header}
										context={header.getContext()}
									/>
								{/if}
							</Table.Head>
						{/each}
					</Table.Row>
				{/each}
			</Table.Header>
			<Table.Body>
				{#each table.getRowModel().rows as row (row.id)}
					<Table.Row 
						data-state={row.getIsSelected() && "selected"}
						class="cursor-pointer transition-colors hover:bg-muted/50 {selectedId === (row.original as any).id ? 'bg-muted' : ''}"
						onclick={() => onRowClick && onRowClick(row.original)}
					>
						{#each row.getVisibleCells() as cell (cell.id)}
							<Table.Cell class="whitespace-nowrap">
								<FlexRender
									content={cell.column.columnDef.cell}
									context={cell.getContext()}
								/>
							</Table.Cell>
						{/each}
					</Table.Row>
				{:else}
					<Table.Row>
						<Table.Cell colspan={columns.length} class="h-24 text-center">
							No hay resultados.
						</Table.Cell>
					</Table.Row>
				{/each}
				
				<!-- Loading Trigger - Se activa cuando es visible -->
				{#if hasMore}
					<Table.Row>
						<Table.Cell colspan={columns.length} class="h-20 text-center">
							<div bind:this={loadingTrigger}>
								{#if loading}
									<div class="flex items-center justify-center gap-2">
										<div class="h-4 w-4 animate-spin rounded-full border-2 border-primary border-t-transparent"></div>
										<span class="text-muted-foreground text-sm">Cargando más...</span>
									</div>
								{:else}
									<div class="text-muted-foreground text-sm">
										Desplázate para cargar más
									</div>
								{/if}
							</div>
						</Table.Cell>
					</Table.Row>
				{/if}
			</Table.Body>
		</Table.Root>
	</div>
	<div
		class="sticky bottom-0 z-30 h-5 overflow-x-scroll overflow-y-hidden border-x border-t bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/80 [scrollbar-gutter:stable]"
		bind:this={bottomScrollbar}
		onscroll={handleBottomHorizontalScroll}
	>
		<div class="h-full min-w-full" bind:this={bottomScrollbarInner}></div>
	</div>
</div>
