<script lang="ts">
	import { onMount, tick } from 'svelte';
	import { getLocale } from '$lib/paraglide/runtime';
	import {
		AuditLogAPI,
		type AuditLog,
		type AuditLogParams
	} from '$lib/api/dashboard/a76/audit_log';
	import * as Card from '$lib/components/ui/card';
	import { Button } from '$lib/components/ui/button';
	import { Input } from '$lib/components/ui/input';
	import * as Table from '$lib/components/ui/table';
	import { translateAuditMovement, translateAuditProcedure } from '$lib/utils/audit-log-i18n';
	import { RefreshCw, Search } from 'lucide-svelte';
	import { companyStore } from '$lib/stores/company.svelte';

	let logs = $state<AuditLog[]>([]);
	let total = $state(0);
	let page = $state(1);
	const pageSize = 50;
	let loading = $state(false);
	let error = $state<string | null>(null);

	let search = $state('');
	let usernameFilter = $state('');
	let procedureFilter = $state('');
	let dateFrom = $state('');
	let dateTo = $state('');

	let procedures = $state<string[]>([]);

	let hasMore = $state(true);
	let sentinel: HTMLElement;

	function isSpanish() {
		return getLocale() === 'es';
	}

	function text(es: string, en: string) {
		return isSpanish() ? es : en;
	}

	function activeCompanyId(): number | undefined {
		return companyStore.activeCompany?.id;
	}

	async function loadLogs() {
		if (loading) return;
		const cid = activeCompanyId();
		if (!cid) {
			error = text('Selecciona una compañía activa.', 'Select an active company.');
			logs = [];
			total = 0;
			hasMore = false;
			return;
		}
		loading = true;
		error = null;
		try {
			const params: AuditLogParams = {
				company_id: cid,
				page,
				page_size: pageSize,
				search: search || undefined,
				username: usernameFilter || undefined,
				procedure: procedureFilter || undefined,
				date_from: dateFrom || undefined,
				date_to: dateTo || undefined
			};

			const response = await AuditLogAPI.getLogs(params);

			if (page === 1) {
				logs = response.data;
			} else {
				logs = [...logs, ...response.data];
			}

			total = response.total;
			hasMore = logs.length < total;
		} catch (e: unknown) {
			error = e instanceof Error ? e.message : String(e);
		} finally {
			loading = false;
		}
	}

	async function loadProcedures() {
		const cid = activeCompanyId();
		if (!cid) {
			procedures = [];
			return;
		}
		try {
			procedures = await AuditLogAPI.getProcedures(cid);
		} catch (e) {
			console.error(e);
		}
	}

	let timer: ReturnType<typeof setTimeout>;

	function handleFilterChange() {
		page = 1;
		hasMore = true;
		logs = [];
		loadLogs();
	}

	function handleSearchInput() {
		clearTimeout(timer);
		timer = setTimeout(() => {
			page = 1;
			hasMore = true;
			logs = [];
			loadLogs();
		}, 300);
	}

	function clearFilters() {
		search = '';
		usernameFilter = '';
		procedureFilter = '';
		dateFrom = '';
		dateTo = '';
		handleFilterChange();
	}

	function formatDate(dateStr: string, timestamp?: string): string {
		const locale = isSpanish() ? 'es-MX' : 'en-US';
		if (timestamp) {
			return new Date(timestamp).toLocaleDateString(locale);
		}
		if (!dateStr) return '';
		const [y, m, d] = dateStr.split('-');
		return isSpanish() ? `${d}/${m}/${y}` : `${m}/${d}/${y}`;
	}

	function formatTime(timeStr: string, timestamp?: string): string {
		const locale = isSpanish() ? 'es-MX' : 'en-US';
		if (timestamp) {
			return new Date(timestamp).toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit' });
		}
		if (!timeStr) return '';
		try {
			const [h, m] = timeStr.split(':');
			const rawHour = parseInt(h, 10);
			if (isSpanish()) {
				const date = new Date();
				date.setHours(rawHour, parseInt(m, 10), 0, 0);
				return date.toLocaleTimeString(locale, { hour: '2-digit', minute: '2-digit' });
			}
			const hour = rawHour % 12 || 12;
			const ampm = rawHour >= 12 ? 'PM' : 'AM';
			return `${hour.toString().padStart(2, '0')}:${m} ${ampm}`;
		} catch {
			return timeStr;
		}
	}

	$effect(() => {
		const cid = companyStore.activeCompany?.id;
		if (!cid) {
			logs = [];
			total = 0;
			procedures = [];
			loading = false;
			return;
		}
		page = 1;
		hasMore = true;
		logs = [];
		loading = false;
		// Run async loaders outside effect tracking to avoid reactive loops.
		queueMicrotask(() => {
			void loadProcedures();
			void loadLogs();
		});
	});

	onMount(() => {
		const observer = new IntersectionObserver(
			(entries) => {
				if (entries[0]?.isIntersecting && hasMore && !loading) {
					page++;
					void loadLogs();
				}
			},
			{ rootMargin: '100px' }
		);

		let cancelled = false;
		void tick().then(() => {
			if (!cancelled && sentinel) {
				observer.observe(sentinel);
			}
		});

		return () => {
			cancelled = true;
			observer.disconnect();
		};
	});
</script>

<div class="flex min-h-0 flex-1 flex-col gap-4">
	<Card.Root class="flex min-h-0 flex-1 flex-col overflow-hidden">
		<Card.Header class="flex-none py-3">
			<div class="flex min-w-0 flex-col gap-2 md:flex-row md:items-center md:justify-between">
				<div class="shrink-0">
					<Card.Title>{text('Bitácora de Auditoría', 'Audit Log')}</Card.Title>
					<Card.Description class="text-xs">{text(`Mostrando ${logs.length} de ${total} registros`, `Showing ${logs.length} of ${total} records`)}</Card.Description>
				</div>
				<div class="flex w-full max-w-full min-w-0 items-center gap-2 overflow-x-auto overflow-y-hidden whitespace-nowrap pb-1 [scrollbar-gutter:stable] [scrollbar-width:thin] md:w-auto">
					<div class="relative shrink-0">
						<Search class="absolute top-2.5 left-2 h-4 w-4 text-muted-foreground" />
						<Input
							id="search"
							placeholder={text('Ref, Mov, Usuario...', 'Ref, Move, User...')}
							class="h-9 w-48 pl-8"
							bind:value={search}
							oninput={handleSearchInput}
						/>
					</div>
					<Input
						id="username"
						placeholder={text('Usuario', 'User')}
						class="h-9 w-32 shrink-0"
						bind:value={usernameFilter}
						oninput={handleSearchInput}
					/>
					<select
						id="procedure"
						bind:value={procedureFilter}
						onchange={handleFilterChange}
						class="flex h-9 w-[180px] shrink-0 rounded-md border border-input bg-background px-3 py-1 text-sm shadow-sm ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:outline-none"
						title={text('Procedimiento', 'Procedure')}
					>
						<option value="">{text('Procedimiento: Todos', 'Procedure: All')}</option>
						{#each procedures as proc}
							<option value={proc}>{translateAuditProcedure(proc)}</option>
						{/each}
					</select>
					<Input
						id="dateFrom"
						type="date"
						class="h-9 w-32 shrink-0"
						bind:value={dateFrom}
						onchange={handleFilterChange}
						title={text('Desde', 'From')}
					/>
					<span class="shrink-0 text-sm text-muted-foreground">-</span>
					<Input
						id="dateTo"
						type="date"
						class="h-9 w-32 shrink-0"
						bind:value={dateTo}
						onchange={handleFilterChange}
						title={text('Hasta', 'To')}
					/>
					<Button variant="outline" size="sm" class="h-9 shrink-0" onclick={clearFilters}>
						{text('Limpiar', 'Clear')}
					</Button>
					<Button
						variant="outline"
						size="sm"
						class="h-9 shrink-0"
						onclick={() => {
							page = 1;
							hasMore = true;
							logs = [];
							void loadLogs();
						}}
						disabled={loading}
					>
						<RefreshCw class="mr-2 h-4 w-4 {loading ? 'animate-spin' : ''}" />
						{text('Actualizar', 'Refresh')}
					</Button>
				</div>
			</div>
		</Card.Header>
		<Card.Content class="flex min-h-0 flex-1 flex-col p-0 px-6 pb-6">
			{#if error}
				<div class="rounded-md bg-red-50 p-4 text-center text-red-500 dark:bg-red-950/30 dark:text-red-400">
					{text('Error al cargar datos', 'Error loading data')}: {error}
				</div>
			{:else}
				<div class="relative min-h-0 flex-1 overflow-y-auto rounded-md border bg-card shadow-inner">
					<Table.Root>
						<Table.Header class="sticky top-0 z-10 bg-background/95 shadow-sm backdrop-blur-sm">
							<Table.Row>
								<Table.Head class="w-[80px]">ID</Table.Head>
								<Table.Head class="w-[180px]">{text('Referencia', 'Reference')}</Table.Head>
								<Table.Head>{text('Procedimiento', 'Procedure')}</Table.Head>
								<Table.Head>{text('Movimiento', 'Movement')}</Table.Head>
								<Table.Head class="w-[150px]">{text('Usuario', 'User')}</Table.Head>
								<Table.Head class="w-[120px]">{text('Fecha', 'Date')}</Table.Head>
								<Table.Head class="w-[120px]">{text('Hora', 'Time')}</Table.Head>
							</Table.Row>
						</Table.Header>
						<Table.Body>
							{#if loading && logs.length === 0}
								<Table.Row>
									<Table.Cell colspan={7} class="h-24 text-center text-muted-foreground italic">
										{text('Cargando...', 'Loading...')}
									</Table.Cell>
								</Table.Row>
							{:else if logs.length === 0}
								<Table.Row>
									<Table.Cell colspan={7} class="h-24 text-center text-muted-foreground">
										{text('No se encontraron registros', 'No records found')}
									</Table.Cell>
								</Table.Row>
							{:else}
								{#each logs as log}
									<Table.Row class="transition-colors hover:bg-muted/50">
										<Table.Cell class="text-xs font-medium text-muted-foreground">{log.spec_id}</Table.Cell>
										<Table.Cell class="text-sm font-bold text-blue-600 dark:text-blue-400">
											{log.reference}
										</Table.Cell>
										<Table.Cell class="text-sm">{translateAuditProcedure(log.procedure)}</Table.Cell>
										<Table.Cell class="text-sm">{translateAuditMovement(log.movement)}</Table.Cell>
										<Table.Cell class="text-sm">{log.username}</Table.Cell>
										<Table.Cell class="text-sm">{formatDate(log.date, log.timestamp)}</Table.Cell>
										<Table.Cell class="text-sm">{formatTime(log.time, log.timestamp)}</Table.Cell>
									</Table.Row>
								{/each}
							{/if}
						</Table.Body>
					</Table.Root>

					<div bind:this={sentinel} class="flex h-12 w-full items-center justify-center p-4">
						{#if loading && logs.length > 0}
							<div class="flex items-center gap-2">
								<RefreshCw class="h-4 w-4 animate-spin text-primary" />
								<span class="text-sm text-muted-foreground">{text('Cargando más registros...', 'Loading more records...')}</span>
							</div>
						{/if}
					</div>
				</div>
			{/if}
		</Card.Content>
	</Card.Root>
</div>
