<script lang="ts">
	import { goto } from '$app/navigation';
	import { browser } from '$app/environment';
	import { page } from '$app/stores';
	import { Button } from '$lib/components/ui/button';
	import * as Card from '$lib/components/ui/card';
	import { Input } from '$lib/components/ui/input';
	import { Skeleton } from '$lib/components/ui/skeleton';
	import { toast } from 'svelte-sonner';
	import { SvelteDate } from 'svelte/reactivity';
	import { authStore } from '$lib/stores/auth.svelte';
	import { apiFetch } from '$lib/utils/api';

	// Types
	type Service = {
		service_id: string;
		booking_id: string;
		service_name: string;
		price: number;
		duration_minutes: number;
		override_price?: number;
		override_duration_minutes?: number;
	};

	type Booking = {
		id: string;
		start_time: string;
		status: string;
		services: Service[];
		total_amount: number;
		amount_paid: number;
		duration_minutes: number;
	};

	// State
	let booking = $state<Booking | null>(null);
	let loading = $state(true);
	let error = $state<string | null>(null);
	let paymentState = $state<'idle' | 'processing' | 'success' | 'error'>('idle');
	let pageState = $state<'loading' | 'authorized' | 'unauthorized' | 'admin'>('loading');

	// Tip selection state
	let selectedTip = $state<number | null>(null);
	let customTip = $state('');
	const tipAmount = $derived(
		selectedTip !== null ? selectedTip : customTip ? parseFloat(customTip) || 0 : 0
	);

	// Get booking ID from URL
	const bookingId = $derived($page.params.id);

	const tipPercentages = $derived.by(() => {
		const total = booking?.total_amount ?? 0;
		if (total <= 0) return [];
		return [
			{ pct: 10, amount: Math.round(total * 0.1 * 100) / 100 },
			{ pct: 15, amount: Math.round(total * 0.15 * 100) / 100 },
			{ pct: 20, amount: Math.round(total * 0.2 * 100) / 100 }
		];
	});

	// Format functions
	function formatDate(dateStr: string): string {
		const date = new SvelteDate(dateStr);
		return date.toLocaleDateString('en-GB', {
			weekday: 'long',
			day: 'numeric',
			month: 'long',
			year: 'numeric'
		});
	}

	function formatTimeRange(
		startStr: string,
		services: Service[],
		fallbackDuration: number
	): string {
		const start = new SvelteDate(startStr);
		const totalMinutes =
			services?.reduce(
				(sum, s) => sum + (s.override_duration_minutes ?? s.duration_minutes ?? 0),
				0
			) ??
			fallbackDuration ??
			0;
		const end = new SvelteDate(start.getTime() + totalMinutes * 60000);

		const formatOpt: Intl.DateTimeFormatOptions = {
			hour: 'numeric',
			minute: '2-digit',
			hour12: true
		};

		return `${start.toLocaleTimeString('en-GB', formatOpt)} – ${end.toLocaleTimeString('en-GB', formatOpt)}`;
	}

	function formatPrice(pounds: number): string {
		return `£${pounds.toFixed(2)}`;
	}

	// Fetch booking data
	async function fetchBookingData() {
		loading = true;
		error = null;

		try {
			const response = await apiFetch(`/api/bookings/${bookingId}`);

			if (!response.ok) {
				if (response.status === 401) {
					throw new Error('Authentication required');
				}
				if (response.status === 404) {
					throw new Error('Booking not found');
				}
				throw new Error('Failed to load booking');
			}

			booking = await response.json();
		} catch (err) {
			error = err instanceof Error ? err.message : 'An error occurred';
		} finally {
			loading = false;
		}
	}

	// Handle tip selection
	function selectTip(amount: number) {
		selectedTip = amount;
		customTip = '';
	}

	function handleCustomTipInput(e: Event) {
		const input = e.target as HTMLInputElement;
		const cleaned = input.value.replace(/[^0-9.]/g, '');
		const firstDot = cleaned.indexOf('.');
		let sanitized: string;
		if (firstDot !== -1) {
			const integerPart = cleaned.substring(0, firstDot);
			const decimalPart = cleaned.substring(firstDot + 1).replace(/\./g, '');
			sanitized = integerPart + '.' + decimalPart;
		} else {
			sanitized = cleaned;
		}
		if (/^\d+(\.\d{0,2})?$/.test(sanitized) || sanitized === '') {
			customTip = sanitized;
		}
		selectedTip = null;
	}

	// Submit tip payment
	async function submitTip() {
		if (!booking) return;
		if (tipAmount <= 0) {
			toast.error('Please select a tip amount');
			return;
		}

		paymentState = 'processing';

		try {
			const amountInPence = Math.round(tipAmount * 100);

			const response = await apiFetch(`/api/bookings/${bookingId}/tip`, {
				method: 'POST',
				headers: { 'Content-Type': 'application/json' },
				body: JSON.stringify({
					amount: amountInPence,
					card_token: 'placeholder'
				})
			});

			if (!response.ok) {
				const errorText = await response.text();
				throw new Error(errorText || 'Payment failed');
			}

			paymentState = 'success';
			toast.success('Thank you for your tip!');
		} catch (err) {
			paymentState = 'error';
			const errorMessage = err instanceof Error ? err.message : 'Payment failed';
			toast.error(errorMessage);
		}
	}

	// Reset and retry
	function retryPayment() {
		paymentState = 'idle';
	}

	// Auth check + fetch
	$effect(() => {
		if (!browser) return;

		if (authStore.isLoading) {
			pageState = 'loading';
			return;
		}

		if (!authStore.isAuthenticated) {
			pageState = 'unauthorized';
			// eslint-disable-next-line svelte/no-navigation-without-resolve
			goto('/login', { replaceState: true });
			return;
		}

		if (authStore.currentUser?.role === 'admin') {
			pageState = 'admin';
			// eslint-disable-next-line svelte/no-navigation-without-resolve
			goto('/admin', { replaceState: true });
			return;
		}

		pageState = 'authorized';
		if (bookingId) {
			fetchBookingData();
		}
	});
</script>

<svelte:head>
	<script>
		(function () {
			// Pre-hydration auth guard: reads localStorage directly because the Svelte
			// authStore hasn't initialized yet at this point (async+$state). This runs
			// synchronously before any rendering, preventing a flash of protected content.
			// The authStore handles post-hydration auth.
			try {
				var token = localStorage.getItem('authToken');
				if (!token) {
					window.location.replace('/login');
					return;
				}
				var payload = JSON.parse(atob(token.split('.')[1]));
				if (payload.exp * 1000 <= Date.now()) {
					window.location.replace('/login');
				}
			} catch (e) {
				window.location.replace('/login');
			}
		})();
	</script>
	<title>Leave a Tip - Crussell</title>
</svelte:head>

<div class="mx-auto min-h-screen px-4 py-8 sm:max-w-md md:py-12">
	{#if loading || pageState === 'loading'}
		<div class="space-y-6">
			<div class="text-center">
				<Skeleton class="mx-auto h-10 w-40" />
			</div>
			<Card.Root>
				<Card.Content class="space-y-4 pt-6">
					<Skeleton class="h-16 w-full" />
					<Skeleton class="h-24 w-full" />
				</Card.Content>
			</Card.Root>
		</div>
	{:else if error}
		<Card.Root>
			<Card.Header>
				<Card.Title class="text-red-600">Something went wrong</Card.Title>
			</Card.Header>
			<Card.Content>
				<p class="text-gray-600">{error}</p>
				<div class="mt-4 flex flex-col gap-2 sm:flex-row">
					<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
					<Button class="w-full sm:w-auto" onclick={() => goto('/')}>Go Home</Button>
					<Button variant="outline" class="w-full sm:w-auto" onclick={fetchBookingData}>
						Try Again
					</Button>
				</div>
			</Card.Content>
		</Card.Root>
	{:else if booking}
		<div class="mb-6 text-center">
			<h1 class="text-2xl font-bold text-gray-900 sm:text-3xl">Leave a Tip</h1>
			<p class="mt-1 text-gray-600">Show your appreciation for great service</p>
		</div>

		{#if paymentState === 'success'}
			<Card.Root>
				<Card.Content class="py-8 text-center">
					<div
						class="mx-auto mb-4 flex h-16 w-16 items-center justify-center rounded-full bg-green-100"
					>
						<svg
							class="h-8 w-8 text-green-600"
							viewBox="0 0 24 24"
							fill="none"
							stroke="currentColor"
							stroke-width="2"
						>
							<path d="M20 6L9 17l-5-5" stroke-linecap="round" stroke-linejoin="round" />
						</svg>
					</div>
					<h2 class="text-xl font-semibold text-gray-900">Thank you!</h2>
					<p class="mt-2 text-gray-600">Your generosity is greatly appreciated.</p>
					<!-- eslint-disable-next-line svelte/no-navigation-without-resolve -->
					<Button class="mt-6" onclick={() => goto('/')}>Go Home</Button>
				</Card.Content>
			</Card.Root>
		{:else}
			<Card.Root class="mb-6">
				<Card.Header>
					<Card.Title>Your Appointment</Card.Title>
				</Card.Header>
				<Card.Content class="space-y-3">
					<div class="flex justify-between">
						<span class="text-sm text-gray-500">Date</span>
						<span class="font-medium">{formatDate(booking.start_time)}</span>
					</div>
					<div class="flex justify-between">
						<span class="text-sm text-gray-500">Time</span>
						<span class="font-medium"
							>{formatTimeRange(
								booking.start_time,
								booking.services,
								booking.duration_minutes ?? 0
							)}</span
						>
					</div>
					<div class="flex justify-between">
						<span class="text-sm text-gray-500">Paid</span>
						<span class="font-medium">{formatPrice(booking.amount_paid ?? 0)}</span>
					</div>
					<div class="border-t pt-3">
						<div class="text-sm text-gray-500">Services</div>
						<div class="mt-2 space-y-1">
							{#each booking.services as service (service.service_id || service.booking_id)}
								<div class="flex justify-between text-sm">
									<span class="text-gray-700">{service.service_name}</span>
									<span class="text-gray-500"
										>{formatPrice(service.override_price ?? service.price)}</span
									>
								</div>
							{/each}
						</div>
					</div>
				</Card.Content>
			</Card.Root>

			<Card.Root class="mb-6">
				<Card.Header>
					<Card.Title>Choose Tip Amount</Card.Title>
				</Card.Header>
				<Card.Content class="space-y-4">
					<div class="grid grid-cols-3 gap-3">
						{#each tipPercentages as tip (tip.pct)}
							<button
								class="rounded-lg border border-input bg-background py-3 text-center font-semibold transition-colors hover:bg-fuchsia-50 {selectedTip ===
								tip.amount
									? 'bg-fuchsia-100'
									: ''}"
								onclick={() => selectTip(tip.amount)}
								type="button"
							>
								<div>{formatPrice(tip.amount)}</div>
								<div class="text-xs font-normal text-gray-500">{tip.pct}%</div>
							</button>
						{/each}
					</div>

					<div>
						<label for="custom-tip" class="text-sm font-medium text-gray-700"
							>Or enter custom amount</label
						>
						<div class="relative mt-1">
							<span class="absolute top-1/2 left-3 -translate-y-1/2 text-gray-500">£</span>
							<Input
								id="custom-tip"
								type="text"
								inputmode="decimal"
								step="0.01"
								min="0"
								placeholder="0.00"
								class="pl-7"
								value={customTip}
								oninput={handleCustomTipInput}
							/>
						</div>
					</div>
				</Card.Content>
			</Card.Root>

			{#if paymentState === 'error'}
				<div class="mb-4 rounded-lg border border-red-200 bg-red-50 p-4">
					<p class="text-red-700">Payment failed. Please try again.</p>
					<Button variant="outline" class="mt-3 w-full" onclick={retryPayment}>Try Again</Button>
				</div>
			{/if}

			<Button
				class="w-full"
				size="lg"
				disabled={tipAmount <= 0 || paymentState === 'processing'}
				loading={paymentState === 'processing'}
				onclick={submitTip}
			>
				{paymentState === 'processing' ? 'Processing...' : `Pay Tip £${tipAmount.toFixed(2)}`}
			</Button>

			<p class="mt-4 text-center text-xs text-gray-500">Secure payment powered by Square</p>
		{/if}
	{/if}
</div>
