<script lang="ts">
	import { fade, scale } from 'svelte/transition';
	import { GenerateServicesByMonthStore } from '$houdini';
	import { SvelteDate, SvelteSet } from 'svelte/reactivity';
	import IconSpinner from '$lib/components/icons/IconSpinner.svelte';

	interface Schedule {
		id: string;
		name: string | null;
		startDate: string;
		endDate: string | null;
		mondayService: boolean;
		tuesdayService: boolean;
		wednesdayService: boolean;
		thursdayService: boolean;
		fridayService: boolean;
		saturdayService: boolean;
		sundayService: boolean;
		weekendService: boolean;
	}

	interface Address {
		id: string;
		name: string | null;
		streetAddress: string;
		city: string;
		state: string;
		zipCode: string;
		isActive: boolean;
		schedules: Schedule[];
	}

	interface Account {
		id: string;
		name: string;
		addresses: Address[];
	}

	interface Props {
		open: boolean;
		accounts: Account[];
		preselectedAddressId?: string;
		preselectedScheduleId?: string;
		initialMonth?: number;
		initialYear?: number;
		onClose: () => void;
		onSuccess: (totalCount: number) => void;
	}

	let {
		open = $bindable(false),
		accounts,
		preselectedAddressId,
		preselectedScheduleId,
		initialMonth,
		initialYear,
		onClose,
		onSuccess
	}: Props = $props();

	// State
	let now = new Date();
	// Default to next month if no initial values provided
	let defaultMonth = now.getMonth() + 2 > 12 ? 1 : now.getMonth() + 2;
	let defaultYear = now.getMonth() + 2 > 12 ? now.getFullYear() + 1 : now.getFullYear();
	let selectedMonth = $state(initialMonth ?? defaultMonth);
	let selectedYear = $state(initialYear ?? defaultYear);

	// Update selected month/year when initial values change
	$effect(() => {
		if (initialMonth !== undefined) {
			selectedMonth = initialMonth;
		}
		if (initialYear !== undefined) {
			selectedYear = initialYear;
		}
	});
	let selectedItems = new SvelteSet<string>(); // "addressId:scheduleId"
	let generating = $state(false);
	let results = $state<
		{ key: string; accountName: string; success: boolean; count?: number; error?: string }[]
	>([]);
	let showResults = $state(false);

	const generateStore = new GenerateServicesByMonthStore();

	// Filter accounts to only show those with active schedules
	// A schedule is active if it has no endDate OR if the endDate is in the future
	let accountsWithActiveSchedules = $derived(
		accounts
			.map((account) => ({
				...account,
				addresses: account.addresses
					.filter((addr) => addr.isActive)
					.map((addr) => ({
						...addr,
						activeSchedules: addr.schedules.filter((s) => {
							if (!s.endDate) return true;
							// Compare endDate with today
							const endDate = new Date(s.endDate + 'T00:00:00');
							const today = new SvelteDate();
							today.setHours(0, 0, 0, 0);
							return endDate >= today;
						})
					}))
					.filter((addr) => addr.activeSchedules.length > 0)
			}))
			.filter((account) => account.addresses.length > 0)
	);

	// Initialize preselection
	$effect(() => {
		if (open && preselectedAddressId && preselectedScheduleId) {
			selectedItems.add(`${preselectedAddressId}:${preselectedScheduleId}`);
		}
	});

	// Reset state when modal opens
	$effect(() => {
		if (open) {
			results = [];
			showResults = false;
			if (!preselectedAddressId) {
				selectedItems.clear();
			}
		}
	});

	function toggleSelection(addressId: string, scheduleId: string) {
		const key = `${addressId}:${scheduleId}`;
		if (selectedItems.has(key)) {
			selectedItems.delete(key);
		} else {
			selectedItems.add(key);
		}
	}

	function selectAll() {
		for (const account of accountsWithActiveSchedules) {
			for (const address of account.addresses) {
				for (const schedule of address.activeSchedules) {
					selectedItems.add(`${address.id}:${schedule.id}`);
				}
			}
		}
	}

	function selectNone() {
		selectedItems.clear();
	}

	function getScheduleDays(schedule: Schedule): string[] {
		const days: string[] = [];
		if (schedule.mondayService) days.push('Mon');
		if (schedule.tuesdayService) days.push('Tue');
		if (schedule.wednesdayService) days.push('Wed');
		if (schedule.thursdayService) days.push('Thu');
		if (schedule.fridayService) days.push('Fri');
		if (schedule.saturdayService) days.push('Sat');
		if (schedule.sundayService) days.push('Sun');
		if (schedule.weekendService && !days.includes('Fri')) days.push('Weekend');
		return days;
	}

	// Calculate estimated service count for a schedule
	// Mirrors backend logic: Mon-Thu use day flags, Fri uses weekend_service OR friday flag,
	// Sat-Sun use day flags only if weekend_service is false
	function estimateServiceCount(schedule: Schedule): number {
		const year = selectedYear;
		const month = selectedMonth;
		const firstDay = new Date(year, month - 1, 1);
		const lastDay = new Date(year, month, 0);

		// Map JS getDay() (Sun=0..Sat=6) to day flags
		// Index: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
		const dayFlags = [
			schedule.sundayService,
			schedule.mondayService,
			schedule.tuesdayService,
			schedule.wednesdayService,
			schedule.thursdayService,
			schedule.fridayService,
			schedule.saturdayService
		];

		let count = 0;
		for (let d = new SvelteDate(firstDay); d <= lastDay; d.setDate(d.getDate() + 1)) {
			const jsDay = d.getDay(); // Sun=0, Mon=1, ..., Sat=6

			let scheduleToday = false;

			if (jsDay >= 1 && jsDay <= 4) {
				// Mon-Thu: use the day flag
				scheduleToday = dayFlags[jsDay];
			} else if (jsDay === 5) {
				// Friday: weekend_service takes precedence, otherwise use friday flag
				scheduleToday = schedule.weekendService || dayFlags[5];
			} else {
				// Sat (6) or Sun (0): only use day flag if weekend_service is OFF
				if (!schedule.weekendService) {
					scheduleToday = dayFlags[jsDay];
				}
			}

			if (scheduleToday) {
				count++;
			}
		}
		return count;
	}

	async function handleGenerate() {
		if (selectedItems.size === 0) return;

		generating = true;
		results = [];

		for (const key of selectedItems) {
			const [addressId, scheduleId] = key.split(':');

			// Find account name for display
			let accountName = 'Unknown';
			for (const account of accounts) {
				if (account.addresses.some((a) => a.id === addressId)) {
					accountName = account.name;
					break;
				}
			}

			try {
				const res = await generateStore.mutate({
					input: {
						accountAddressId: addressId,
						scheduleId: scheduleId,
						year: selectedYear,
						month: selectedMonth
					}
				});

				const count = res.data?.generateServicesByMonth?.length ?? 0;
				results = [...results, { key, accountName, success: true, count }];
			} catch (err) {
				const errorMessage = err instanceof Error ? err.message : 'Failed to generate';
				results = [...results, { key, accountName, success: false, error: errorMessage }];
			}
		}

		generating = false;
		showResults = true;

		// Calculate total and notify
		const totalCount = results.reduce((sum, r) => sum + (r.count ?? 0), 0);
		if (totalCount > 0) {
			onSuccess(totalCount);
		}
	}

	function handleClose() {
		if (generating) return;
		open = false;
		onClose();
	}

	function handleKeydown(event: KeyboardEvent) {
		if (event.key === 'Escape' && open && !generating) {
			handleClose();
		}
	}

	function handleBackdropClick(event: MouseEvent) {
		if (event.target === event.currentTarget && !generating) {
			handleClose();
		}
	}

	// Month names
	const months = [
		'January',
		'February',
		'March',
		'April',
		'May',
		'June',
		'July',
		'August',
		'September',
		'October',
		'November',
		'December'
	];

	// Year options (current year and next 2)
	let yearOptions = $derived([now.getFullYear(), now.getFullYear() + 1, now.getFullYear() + 2]);
</script>

<svelte:window onkeydown={handleKeydown} />

{#if open}
	<div
		class="fixed inset-0 z-50 flex items-center justify-center bg-black/50 p-4"
		transition:fade={{ duration: 150 }}
		onclick={handleBackdropClick}
		role="presentation"
	>
		<div
			class="flex max-h-[90vh] w-full max-w-2xl flex-col rounded-xl border border-theme bg-theme shadow-theme-lg"
			transition:scale={{ duration: 150, start: 0.95 }}
			role="dialog"
			aria-modal="true"
			aria-labelledby="modal-title"
		>
			<!-- Header -->
			<div class="flex items-center justify-between border-b border-theme px-6 py-4">
				<h2 id="modal-title" class="text-lg font-semibold text-theme">Generate Services</h2>
				<button
					onclick={handleClose}
					disabled={generating}
					class="rounded-lg p-1 text-theme-muted transition-colors hover:bg-black/5 hover:text-theme disabled:opacity-50 dark:hover:bg-white/10"
					aria-label="Close"
				>
					<svg class="h-5 w-5" style="fill: none" viewBox="0 0 24 24" stroke="currentColor">
						<path
							stroke-linecap="round"
							stroke-linejoin="round"
							stroke-width="2"
							d="M6 18L18 6M6 6l12 12"
						/>
					</svg>
				</button>
			</div>

			<!-- Content -->
			<div class="flex-1 overflow-y-auto p-6">
				{#if showResults}
					<!-- Results View -->
					<div class="space-y-4">
						<h3 class="font-medium text-theme">Generation Results</h3>
						<div class="space-y-2">
							{#each results as result (result.key)}
								<div class="flex items-center justify-between rounded-lg border border-theme p-3">
									<span class="text-theme">{result.accountName}</span>
									{#if result.success}
										<span
											class="rounded-full bg-green-100 px-2 py-0.5 text-xs font-medium text-green-700 dark:bg-green-900/30 dark:text-green-400"
										>
											{result.count} service{result.count !== 1 ? 's' : ''} created
										</span>
									{:else}
										<span
											class="rounded-full bg-red-100 px-2 py-0.5 text-xs font-medium text-red-700 dark:bg-red-900/30 dark:text-red-400"
										>
											{result.error}
										</span>
									{/if}
								</div>
							{/each}
						</div>
						{#if results.length > 0}
							{@const successCount = results.filter((r) => r.success).length}
							{@const totalServices = results.reduce((sum, r) => sum + (r.count ?? 0), 0)}
							<div class="rounded-lg bg-theme-card p-4 text-center">
								<p class="text-lg font-semibold text-theme">
									{totalServices} service{totalServices !== 1 ? 's' : ''} generated
								</p>
								<p class="text-sm text-theme-muted">
									{successCount} of {results.length} address{results.length !== 1 ? 'es' : ''} succeeded
								</p>
							</div>
						{/if}
					</div>
				{:else}
					<!-- Selection View -->
					<div class="space-y-6">
						<!-- Month/Year Selection -->
						<div class="flex gap-4">
							<div class="flex-1">
								<label for="month-select" class="mb-1 block text-sm font-medium text-theme"
									>Month</label
								>
								<select
									id="month-select"
									bind:value={selectedMonth}
									class="w-full rounded-lg border border-theme bg-theme px-3 py-2 text-theme"
								>
									{#each months as month, i (month)}
										<option value={i + 1}>{month}</option>
									{/each}
								</select>
							</div>
							<div class="w-32">
								<label for="year-select" class="mb-1 block text-sm font-medium text-theme"
									>Year</label
								>
								<select
									id="year-select"
									bind:value={selectedYear}
									class="w-full rounded-lg border border-theme bg-theme px-3 py-2 text-theme"
								>
									{#each yearOptions as year (year)}
										<option value={year}>{year}</option>
									{/each}
								</select>
							</div>
						</div>

						<!-- Selection Controls -->
						<div class="flex items-center justify-between">
							<p class="text-sm text-theme-muted">
								{selectedItems.size} address{selectedItems.size !== 1 ? 'es' : ''} selected
							</p>
							<div class="flex gap-2">
								<button
									onclick={selectAll}
									class="text-sm text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
								>
									Select All
								</button>
								<span class="text-theme-muted">|</span>
								<button
									onclick={selectNone}
									class="text-sm text-primary-500 hover:text-primary-600 dark:hover:text-primary-400"
								>
									Select None
								</button>
							</div>
						</div>

						<!-- Address List -->
						<div class="space-y-3">
							{#if accountsWithActiveSchedules.length === 0}
								<div class="rounded-lg border border-theme bg-theme-card p-8 text-center">
									<p class="text-theme-muted">No accounts with active schedules found</p>
								</div>
							{:else}
								{#each accountsWithActiveSchedules as account (account.id)}
									<div class="rounded-lg border border-theme">
										<div class="border-b border-theme bg-theme-card px-4 py-2">
											<h4 class="font-medium text-theme">{account.name}</h4>
										</div>
										<div class="divide-theme divide-y">
											{#each account.addresses as address (address.id)}
												{#each address.activeSchedules as schedule (schedule.id)}
													{@const key = `${address.id}:${schedule.id}`}
													{@const isSelected = selectedItems.has(key)}
													{@const days = getScheduleDays(schedule)}
													{@const estimatedCount = estimateServiceCount(schedule)}
													<label
														class="flex cursor-pointer items-start gap-3 px-4 py-3 transition-colors hover:bg-black/5 dark:hover:bg-white/5"
													>
														<input
															type="checkbox"
															checked={isSelected}
															onchange={() => toggleSelection(address.id, schedule.id)}
															class="mt-1 h-4 w-4 rounded border-theme text-primary-500"
														/>
														<span class="min-w-0 flex-1">
															<span class="text-sm font-medium text-theme">
																{address.name || address.streetAddress}
															</span>
															<span class="text-xs text-theme-muted">
																{address.streetAddress}, {address.city}, {address.state}
															</span>
															<span class="mt-1 flex flex-wrap items-center gap-1">
																{#each days as day (day)}
																	<span
																		class="rounded bg-primary-100 px-1.5 py-0.5 text-xs font-medium text-primary-700 dark:bg-primary-900/40 dark:text-primary-400"
																	>
																		{day}
																	</span>
																{/each}
																<span class="ml-2 text-xs text-theme-muted">
																	~{estimatedCount} service{estimatedCount !== 1 ? 's' : ''}
																</span>
															</span>
														</span>
													</label>
												{/each}
											{/each}
										</div>
									</div>
								{/each}
							{/if}
						</div>
					</div>
				{/if}
			</div>

			<!-- Footer -->
			<div class="flex justify-end gap-3 border-t border-theme px-6 py-4">
				{#if showResults}
					<button
						onclick={handleClose}
						class="rounded-lg bg-primary-500 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-primary-600"
					>
						Done
					</button>
				{:else}
					<button
						onclick={handleClose}
						disabled={generating}
						class="rounded-lg border border-theme bg-theme px-4 py-2 text-sm font-medium text-theme transition-colors hover:bg-black/5 disabled:opacity-50 dark:hover:bg-white/10"
					>
						Cancel
					</button>
					<button
						onclick={handleGenerate}
						disabled={generating || selectedItems.size === 0}
						class="rounded-lg bg-primary-500 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-primary-600 disabled:cursor-not-allowed disabled:opacity-50"
					>
						{#if generating}
							<span class="flex items-center gap-2">
								<IconSpinner class="h-4 w-4" />
								Generating...
							</span>
						{:else}
							Generate Services
						{/if}
					</button>
				{/if}
			</div>
		</div>
	</div>
{/if}
