<script lang="ts">
	import type { ScheduleSlot } from '$lib/features/schedule/api/schedule';
	import { fetchDaySchedule, fetchWeekSchedule, fetchNextClass } from '$lib/features/schedule/api/schedule';
	import { untrack } from 'svelte';
	import { recordSync, isOffline, getLastSyncDate, prefetchScheduleDays } from '$lib/features/schedule/stores/scheduleCache';
	import DayView from './DayView.svelte';
	import WeekView from './WeekView.svelte';
	import SlotDetails from './SlotDetails.svelte';

	type ViewMode = 'day' | 'week';

	let viewMode = $state<ViewMode>('day');
	let currentDate = $state(todayStr());
	let slots = $state<ScheduleSlot[]>([]);
	let nextSlotId = $state<string | null>(null);
	let isLoading = $state(false);
	let error = $state<string | null>(null);
	let selectedSlot = $state<ScheduleSlot | null>(null);
	let offline = $state(isOffline());
	let lastSync = $derived(getLastSyncDate());

	function formatLocalDate(d: Date): string {
		const y = d.getFullYear();
		const m = String(d.getMonth() + 1).padStart(2, '0');
		const day = String(d.getDate()).padStart(2, '0');
		return `${y}-${m}-${day}`;
	}

	function todayStr(): string {
		return formatLocalDate(new Date());
	}

	function mondayOfWeek(dateStr: string): string {
		const d = new Date(dateStr + 'T00:00:00');
		const day = d.getDay();
		const diff = d.getDate() - day + (day === 0 ? -6 : 1);
		d.setDate(diff);
		return formatLocalDate(d);
	}

	async function loadSchedule() {
		isLoading = true;
		error = null;

		try {
			if (viewMode === 'day') {
				slots = await fetchDaySchedule(currentDate);
			} else {
				slots = await fetchWeekSchedule(currentDate);
			}
			recordSync();

			// Load next class info
			try {
				const next = await fetchNextClass();
				nextSlotId = next?.slotId ?? null;
			} catch {
				nextSlotId = null;
			}
		} catch (e) {
			error = e instanceof Error ? e.message : 'Erreur de chargement';
		} finally {
			isLoading = false;
		}
	}

	// Initial load (in $effect to avoid SSR) + online/offline listener + background prefetch
	$effect(() => {
		untrack(() => {
			loadSchedule();
			// Prefetch next 30 days in background for offline support (AC5)
			prefetchScheduleDays(fetchDaySchedule);
		});

		function handleOnline() {
			offline = false;
			loadSchedule();
		}
		function handleOffline() {
			offline = true;
		}

		window.addEventListener('online', handleOnline);
		window.addEventListener('offline', handleOffline);

		return () => {
			window.removeEventListener('online', handleOnline);
			window.removeEventListener('offline', handleOffline);
		};
	});

	function navigateDay(offset: number) {
		const d = new Date(currentDate + 'T00:00:00');
		d.setDate(d.getDate() + offset);
		currentDate = formatLocalDate(d);
		loadSchedule();
	}

	function navigateWeek(offset: number) {
		const d = new Date(currentDate + 'T00:00:00');
		d.setDate(d.getDate() + offset * 7);
		currentDate = formatLocalDate(d);
		loadSchedule();
	}

	function goToToday() {
		currentDate = todayStr();
		loadSchedule();
	}

	function setViewMode(mode: ViewMode) {
		viewMode = mode;
		loadSchedule();
	}

	// Swipe detection
	let touchStartX = $state(0);

	function handleTouchStart(e: globalThis.TouchEvent) {
		const touch = e.touches[0];
		if (touch) touchStartX = touch.clientX;
	}

	function handleTouchEnd(e: globalThis.TouchEvent) {
		const touch = e.changedTouches[0];
		if (!touch) return;
		const touchEndX = touch.clientX;
		const diff = touchStartX - touchEndX;
		const threshold = 50;

		if (Math.abs(diff) > threshold) {
			if (viewMode === 'day') {
				navigateDay(diff > 0 ? 1 : -1);
			} else {
				navigateWeek(diff > 0 ? 1 : -1);
			}
		}
	}

	function formatSyncDate(iso: string | null): string {
		if (!iso) return '';
		return new Date(iso).toLocaleString('fr-FR', {
			day: '2-digit',
			month: '2-digit',
			hour: '2-digit',
			minute: '2-digit'
		});
	}
</script>

<div class="student-schedule">
	<!-- Header bar -->
	<div class="schedule-header">
		<div class="view-toggle">
			<button class:active={viewMode === 'day'} aria-pressed={viewMode === 'day'} onclick={() => setViewMode('day')}>Jour</button>
			<button class:active={viewMode === 'week'} aria-pressed={viewMode === 'week'} onclick={() => setViewMode('week')}>Semaine</button>
		</div>

		<div class="nav-controls">
			<button class="nav-btn" onclick={() => viewMode === 'day' ? navigateDay(-1) : navigateWeek(-1)} aria-label="Précédent">&lsaquo;</button>
			<button class="today-btn" onclick={goToToday}>Aujourd'hui</button>
			<button class="nav-btn" onclick={() => viewMode === 'day' ? navigateDay(1) : navigateWeek(1)} aria-label="Suivant">&rsaquo;</button>
		</div>
	</div>

	<!-- Offline indicator -->
	{#if offline}
		<div class="offline-banner" role="status">
			<span class="offline-dot"></span>
			<span>Hors ligne</span>
			{#if lastSync}
				<span class="sync-date">Dernière sync : {formatSyncDate(lastSync)}</span>
			{/if}
		</div>
	{/if}

	<!-- Content area with swipe -->
	<div
		class="schedule-content"
		ontouchstart={handleTouchStart}
		ontouchend={handleTouchEnd}
		role="region"
		aria-label="Emploi du temps"
	>
		{#if isLoading}
			<div class="loading">
				<div class="spinner"></div>
				<span>Chargement...</span>
			</div>
		{:else if error}
			<div class="error-state">
				<p>{error}</p>
				<button onclick={loadSchedule}>Réessayer</button>
			</div>
		{:else if viewMode === 'day'}
			<DayView
				{slots}
				date={currentDate}
				{nextSlotId}
				onSlotClick={(slot) => (selectedSlot = slot)}
			/>
		{:else}
			<WeekView
				{slots}
				weekStart={mondayOfWeek(currentDate)}
				onSlotClick={(slot) => (selectedSlot = slot)}
			/>
		{/if}
	</div>
</div>

<!-- Slot detail modal (AC4) -->
{#if selectedSlot}
	<SlotDetails slot={selectedSlot} onClose={() => (selectedSlot = null)} />
{/if}

<style>
	.student-schedule {
		display: flex;
		flex-direction: column;
		gap: 1rem;
	}

	.schedule-header {
		display: flex;
		justify-content: space-between;
		align-items: center;
		flex-wrap: wrap;
		gap: 0.75rem;
	}

	.view-toggle {
		display: flex;
		background: #f3f4f6;
		border-radius: 0.5rem;
		padding: 0.25rem;
	}

	.view-toggle button {
		padding: 0.375rem 1rem;
		font-size: 0.875rem;
		font-weight: 500;
		background: transparent;
		border: none;
		border-radius: 0.375rem;
		cursor: pointer;
		color: #6b7280;
		transition: all 0.15s;
	}

	.view-toggle button.active {
		background: white;
		color: #1f2937;
		box-shadow: 0 1px 2px rgba(0, 0, 0, 0.05);
	}

	.nav-controls {
		display: flex;
		align-items: center;
		gap: 0.25rem;
	}

	.nav-btn {
		width: 2rem;
		height: 2rem;
		display: flex;
		align-items: center;
		justify-content: center;
		background: #f3f4f6;
		border: none;
		border-radius: 0.375rem;
		cursor: pointer;
		font-size: 1.25rem;
		color: #374151;
		transition: background 0.15s;
	}

	.nav-btn:hover {
		background: #e5e7eb;
	}

	.today-btn {
		padding: 0.375rem 0.75rem;
		font-size: 0.75rem;
		font-weight: 500;
		background: #eff6ff;
		color: #3b82f6;
		border: 1px solid #bfdbfe;
		border-radius: 0.375rem;
		cursor: pointer;
		transition: background 0.15s;
	}

	.today-btn:hover {
		background: #dbeafe;
	}

	.offline-banner {
		display: flex;
		align-items: center;
		gap: 0.5rem;
		padding: 0.5rem 0.75rem;
		background: #fef3c7;
		border: 1px solid #fcd34d;
		border-radius: 0.5rem;
		font-size: 0.75rem;
		color: #92400e;
	}

	.offline-dot {
		width: 0.5rem;
		height: 0.5rem;
		border-radius: 50%;
		background: #f59e0b;
		flex-shrink: 0;
	}

	.sync-date {
		margin-left: auto;
		color: #b45309;
	}

	.schedule-content {
		min-height: 200px;
		touch-action: pan-y;
	}

	.loading {
		display: flex;
		align-items: center;
		justify-content: center;
		gap: 0.75rem;
		padding: 3rem;
		color: #6b7280;
	}

	.spinner {
		width: 1.25rem;
		height: 1.25rem;
		border: 2px solid #e5e7eb;
		border-top-color: #3b82f6;
		border-radius: 50%;
		animation: spin 0.8s linear infinite;
	}

	@keyframes spin {
		to {
			transform: rotate(360deg);
		}
	}

	.error-state {
		text-align: center;
		padding: 2rem;
		color: #dc2626;
	}

	.error-state button {
		margin-top: 0.75rem;
		padding: 0.5rem 1rem;
		background: #3b82f6;
		color: white;
		border: none;
		border-radius: 0.375rem;
		cursor: pointer;
	}
</style>
