<script lang="ts">
	import { SvelteDate } from 'svelte/reactivity';
	import { apiFetch } from '$lib/utils/api';
	import { Skeleton } from '$lib/components/ui/skeleton';
	import * as Card from '$lib/components/ui/card';
	import { formatLocalDateTime } from '$lib/utils/timeSlots';

	type TodayAppointment = {
		id: string;
		start_time: string;
		status: string;
		user_name: string;
		user_id: string;
		services: string[];
		duration_minutes: number;
		previous_first_name?: string | null;
		previous_last_name?: string | null;
	};

	type DayWorkingHours = {
		date: string;
		isOpen: boolean;
		startTime: string;
		endTime: string;
	};

	type Stats = {
		total: number;
		completed: number;
		inProgress: number;
		upcoming: number;
		cancelled: number;
		noShow: number;
		occupancyPercent: number;
		bookingsMade: number;
		bookingsMadeOverClosed: boolean;
	};

	let loading = $state(true);
	let stats = $state<Stats | null>(null);
	let prevJson = $state('');
	let initialized = $state(false);

	const today = $derived(new Date().toLocaleDateString('en-CA', { timeZone: 'Europe/London' }));

	function timeToMinutes(time: string): number {
		const [h, m] = time.split(':').map(Number);
		return h * 60 + m;
	}

	async function findLastWorkingDayClose(): Promise<{ cutoff: string; spansClosed: boolean }> {
		const londonDateStr = new Date().toLocaleDateString('en-CA', { timeZone: 'Europe/London' });
		const now = new SvelteDate(londonDateStr + 'T00:00:00Z');
		let spansClosed = false;

		for (let i = 1; i <= 14; i++) {
			const d = new SvelteDate(now);
			d.setDate(d.getDate() - i);
			const dateStr = `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;

			const res = await apiFetch(
				`/api/scheduling/working-hours?start=${encodeURIComponent(dateStr)}&end=${encodeURIComponent(dateStr)}`,
				{
					headers: { 'Content-Type': 'application/json' }
				}
			);

			if (res.ok) {
				const data: DayWorkingHours[] = await res.json();
				const day = (data || []).find((d) => d.date === dateStr);
				if (day?.isOpen) {
					const closeTime = day.endTime;
					const [h, m] = closeTime.split(':').map(Number);
					const closeDate = new SvelteDate(d);
					closeDate.setHours(h, m, 0, 0);
					return { cutoff: formatLocalDateTime(closeDate), spansClosed };
				} else {
					spansClosed = true;
				}
			}
		}

		const fallback = new SvelteDate(now);
		fallback.setDate(fallback.getDate() - 1);
		fallback.setHours(17, 0, 0, 0);
		return { cutoff: formatLocalDateTime(fallback), spansClosed };
	}

	async function fetchTodayStats() {
		if (!initialized) loading = true;
		try {
			const dateParam = today;
			const [apptsRes, whRes] = await Promise.all([
				apiFetch(`/api/admin/today/appointments`, {
					headers: { 'Content-Type': 'application/json' }
				}),
				apiFetch(
					`/api/scheduling/working-hours?start=${encodeURIComponent(dateParam)}&end=${encodeURIComponent(dateParam)}`,
					{
						headers: { 'Content-Type': 'application/json' }
					}
				)
			]);

			let appointments: TodayAppointment[] = [];
			let workingHours: DayWorkingHours | null = null;

			if (apptsRes.ok) {
				const data = await apptsRes.json();
				appointments = data.appointments || [];
			}

			if (whRes.ok) {
				const data: DayWorkingHours[] = await whRes.json();
				workingHours = (data || []).find((d) => d.date === dateParam) ?? null;
			}

			const total = appointments.length;
			const completed = appointments.filter((a) => a.status === 'completed').length;
			const inProgress = appointments.filter((a) => a.status === 'in_progress').length;
			const upcoming = appointments.filter(
				(a) => a.status === 'confirmed' || a.status === 'pending'
			).length;
			const cancelled = appointments.filter(
				(a) => a.status === 'client_cancelled' || a.status === 'we_cancelled'
			).length;
			const noShow = appointments.filter((a) => a.status === 'no_show').length;

			let occupancyPercent = 0;
			if (workingHours?.isOpen) {
				const workingMinutes =
					timeToMinutes(workingHours.endTime) - timeToMinutes(workingHours.startTime);
				const bookedMinutes = appointments
					.filter(
						(a) =>
							a.status !== 'client_cancelled' &&
							a.status !== 'we_cancelled' &&
							a.status !== 'no_show'
					)
					.reduce((sum, a) => sum + a.duration_minutes, 0);
				occupancyPercent =
					workingMinutes > 0 ? Math.round((bookedMinutes / workingMinutes) * 100) : 0;
			}

			const { cutoff, spansClosed } = await findLastWorkingDayClose();
			const nowISO = formatLocalDateTime(new SvelteDate());
			let bookingsMade = 0;
			try {
				const bmRes = await apiFetch(
					`/api/admin/bookings/by-created-range?start=${encodeURIComponent(cutoff)}&end=${encodeURIComponent(nowISO)}`,
					{
						headers: { 'Content-Type': 'application/json' }
					}
				);
				if (bmRes.ok) {
					const data = await bmRes.json();
					bookingsMade = (data.bookings || []).length;
				}
			} catch {
				// Non-critical — bookings-made fetch is optional for stats
			}

			const newStats: Stats = {
				total,
				completed,
				inProgress,
				upcoming,
				cancelled,
				noShow,
				occupancyPercent,
				bookingsMade,
				bookingsMadeOverClosed: spansClosed
			};
			const newJson = JSON.stringify(newStats);
			if (newJson !== prevJson) {
				stats = newStats;
				prevJson = newJson;
			}
		} catch (err) {
			console.error('Error fetching today stats:', err);
		} finally {
			if (!initialized) {
				loading = false;
				initialized = true;
			}
		}
	}

	$effect(() => {
		fetchTodayStats();

		const intervalId = setInterval(fetchTodayStats, 600_000);

		function handleRefresh() {
			fetchTodayStats();
		}
		window.addEventListener('bookingApproved', handleRefresh);

		return () => {
			clearInterval(intervalId);
			window.removeEventListener('bookingApproved', handleRefresh);
		};
	});
</script>

<Card.Root>
	<Card.Header>
		<Card.Title>Today's Stats</Card.Title>
	</Card.Header>
	<Card.Content>
		{#if loading && !stats}
			<div class="space-y-3">
				{#each Array(6) as _, i (i)}
					<Skeleton class="h-5 w-full" />
				{/each}
			</div>
		{:else if stats}
			<div class="space-y-3">
				<div class="flex items-center justify-between">
					<span class="text-sm text-gray-600">Total Appointments</span>
					<span class="text-2xl font-bold">{stats.total}</span>
				</div>
				<hr class="border-gray-100" />
				{#if stats.completed > 0}
					<div class="flex items-center justify-between">
						<span class="text-sm text-gray-600">Completed</span>
						<span class="font-semibold">{stats.completed}</span>
					</div>
				{/if}
				{#if stats.inProgress > 0}
					<div class="flex items-center justify-between">
						<span class="text-sm text-gray-600">In Progress</span>
						<span class="font-semibold">{stats.inProgress}</span>
					</div>
				{/if}
				{#if stats.upcoming > 0}
					<div class="flex items-center justify-between">
						<span class="text-sm text-gray-600">Upcoming</span>
						<span class="font-semibold">{stats.upcoming}</span>
					</div>
				{/if}
				{#if stats.cancelled > 0}
					<div class="flex items-center justify-between">
						<span class="text-sm text-gray-600">Cancelled</span>
						<span class="font-semibold">{stats.cancelled}</span>
					</div>
				{/if}
				{#if stats.noShow > 0}
					<div class="flex items-center justify-between">
						<span class="text-sm text-gray-600">No Show</span>
						<span class="font-semibold">{stats.noShow}</span>
					</div>
				{/if}
				<hr class="border-gray-100" />
				{#if stats.bookingsMade > 0}
					<div class="flex items-center justify-between">
						<span class="text-sm text-gray-600">
							Bookings Made{#if stats.bookingsMadeOverClosed}<sup class="text-xs text-gray-400"
									>*</sup
								>{/if}
						</span>
						<span class="font-semibold">{stats.bookingsMade}</span>
					</div>
				{/if}
				<div class="flex items-center justify-between">
					<span class="text-sm font-medium text-gray-700">Occupancy</span>
					<span class="text-lg font-bold">{stats.occupancyPercent}%</span>
				</div>
			</div>
		{/if}
	</Card.Content>
</Card.Root>
