<script lang="ts">
	import { createEventDispatcher, getContext } from 'svelte';
	import { toast } from 'svelte-sonner';

	import Modal from '$lib/components/common/Modal.svelte';
	import DeleteConfirmDialog from '$lib/components/common/ConfirmDialog.svelte';
	import XMark from '$lib/components/icons/XMark.svelte';
	import Spinner from '$lib/components/common/Spinner.svelte';

	import type { CalendarModel, CalendarEventModel, CalendarEventForm } from '$lib/apis/calendar';
	import {
		createCalendarEvent,
		updateCalendarEvent,
		deleteCalendarEvent
	} from '$lib/apis/calendar';

	const i18n = getContext('i18n');
	const dispatch = createEventDispatcher();

	export let show = false;
	export let event: CalendarEventModel | null = null;
	export let calendars: CalendarModel[] = [];
	export let defaultCalendarId: string = '';
	export let defaultStartAt: number | null = null;

	let title = '';
	let description = '';
	let calendarId = '';
	let startDate = '';
	let startTime = '';
	let endDate = '';
	let endTime = '';
	let allDay = false;
	let location = '';
	let alertMinutes: number = 10;
	let repeatFrequency = '';
	let loading = false;
	let showDeleteConfirmDialog = false;

	const REPEAT_RRULE_MAP: Record<string, string> = {
		daily: 'FREQ=DAILY',
		weekdays: 'FREQ=WEEKLY;BYDAY=MO,TU,WE,TH,FR',
		weekly: 'FREQ=WEEKLY',
		monthly: 'FREQ=MONTHLY',
		yearly: 'FREQ=YEARLY'
	};

	function getRepeatRrule(): string | undefined {
		return REPEAT_RRULE_MAP[repeatFrequency] || undefined;
	}

	function parseRepeatFromRrule(rrule: string | null): string {
		if (!rrule) return '';
		const normalized = rrule.toUpperCase().replace(/\s/g, '');
		for (const [key, value] of Object.entries(REPEAT_RRULE_MAP)) {
			if (normalized === value) return key;
		}
		return '';
	}

	const NS = 1_000_000;

	function nsToDateStr(ns: number): string {
		const d = new Date(ns / NS);
		const year = d.getFullYear();
		const month = String(d.getMonth() + 1).padStart(2, '0');
		const day = String(d.getDate()).padStart(2, '0');
		return `${year}-${month}-${day}`;
	}

	function nsToTimeStr(ns: number): string {
		return new Date(ns / NS).toTimeString().slice(0, 5);
	}

	function dateTimeToNs(dateStr: string, timeStr: string): number {
		return new Date(`${dateStr}T${timeStr || '00:00'}`).getTime() * NS;
	}

	function reset() {
		if (event) {
			title = event.title;
			description = event.description || '';
			calendarId = event.calendar_id;
			startDate = nsToDateStr(event.start_at);
			startTime = nsToTimeStr(event.start_at);
			endDate = event.end_at ? nsToDateStr(event.end_at) : '';
			endTime = event.end_at ? nsToTimeStr(event.end_at) : '';
			allDay = event.all_day;
			location = event.location || '';
			alertMinutes = event.meta?.alert_minutes ?? 10;
			repeatFrequency = parseRepeatFromRrule(event.rrule);
		} else {
			title = '';
			description = '';
			calendarId = defaultCalendarId || (calendars.length > 0 ? calendars[0].id : '');
			if (defaultStartAt) {
				startDate = nsToDateStr(defaultStartAt);
				startTime = nsToTimeStr(defaultStartAt);
				const endNs = defaultStartAt + 60 * 60 * 1000 * NS;
				endDate = nsToDateStr(endNs);
				endTime = nsToTimeStr(endNs);
			} else {
				const now = new Date();
				startDate = now.toISOString().slice(0, 10);
				startTime = now.toTimeString().slice(0, 5);
				const later = new Date(now.getTime() + 60 * 60 * 1000);
				endDate = later.toISOString().slice(0, 10);
				endTime = later.toTimeString().slice(0, 5);
			}
			allDay = false;
			location = '';
			alertMinutes = 10;
			repeatFrequency = '';
		}
	}

	$: if (show) reset();

	const submitHandler = async () => {
		if (!title.trim()) {
			toast.error($i18n.t('Title is required'));
			return;
		}

		loading = true;
		try {
			const startNs = dateTimeToNs(startDate, allDay ? '00:00' : startTime);
			const endNs = endDate ? dateTimeToNs(endDate, allDay ? '23:59' : endTime) : undefined;

			if (event && !event.meta?.automation_id) {
				const result = await updateCalendarEvent(localStorage.token, event.id, {
					calendar_id: calendarId,
					title: title.trim(),
					description: description.trim() || undefined,
					start_at: startNs,
					end_at: endNs,
					all_day: allDay,
					rrule: getRepeatRrule(),
					location: location.trim() || undefined,
					meta: { alert_minutes: alertMinutes }
				});
				if (result) {
					toast.success($i18n.t('Event updated'));
					dispatch('save', result);
					show = false;
				}
			} else {
				const form: CalendarEventForm = {
					calendar_id: calendarId,
					title: title.trim(),
					description: description.trim() || undefined,
					start_at: startNs,
					end_at: endNs,
					all_day: allDay,
					rrule: getRepeatRrule(),
					location: location.trim() || undefined,
					meta: { alert_minutes: alertMinutes }
				};
				const result = await createCalendarEvent(localStorage.token, form);
				if (result) {
					toast.success($i18n.t('Event created'));
					dispatch('save', result);
					show = false;
				}
			}
		} catch (err) {
			toast.error(`${err}`);
		} finally {
			loading = false;
		}
	};

	const deleteHandler = async () => {
		if (!event || event.meta?.automation_id) return;
		loading = true;
		try {
			await deleteCalendarEvent(localStorage.token, event.id);
			toast.success($i18n.t('Event deleted'));
			dispatch('delete', event);
			show = false;
		} catch (err) {
			toast.error(`${err}`);
		} finally {
			loading = false;
		}
	};
</script>

<Modal size="md" bind:show>
	<div>
		<!-- Header -->
		<div class="flex justify-between dark:text-gray-100 px-5 pt-4 pb-2">
			<input
				class="w-full text-lg bg-transparent outline-hidden font-primary placeholder:text-gray-300 dark:placeholder:text-gray-700"
				type="text"
				bind:value={title}
				placeholder={$i18n.t('Event title')}
			/>
			<button
				class="self-center shrink-0 ml-2"
				aria-label={$i18n.t('Close')}
				on:click={() => (show = false)}
			>
				<XMark className="size-5" />
			</button>
		</div>

		<!-- Details -->
		<div class="px-5 pb-2 flex flex-col gap-3">
			<!-- Calendar -->
			<div>
				<div class="mb-1 text-xs text-gray-500">{$i18n.t('Calendar')}</div>
				<select
					class="w-full text-sm bg-transparent outline-hidden cursor-pointer"
					bind:value={calendarId}
				>
					{#each calendars.filter((c) => c.id !== '__scheduled_tasks__') as cal (cal.id)}
						<option value={cal.id}>{cal.name}</option>
					{/each}
				</select>
			</div>

			<!-- Date / Time -->
			<div>
				<div class="mb-1 text-xs text-gray-500">{$i18n.t('When')}</div>
				<div class="flex items-center gap-2 text-sm flex-wrap">
					<input type="date" class="bg-transparent outline-hidden" bind:value={startDate} />
					{#if !allDay}
						<input type="time" class="bg-transparent outline-hidden" bind:value={startTime} />
						<span class="text-gray-300 dark:text-gray-600">–</span>
						<input type="time" class="bg-transparent outline-hidden" bind:value={endTime} />
					{/if}
					<label class="flex items-center gap-1.5 cursor-pointer text-xs text-gray-400 ml-auto">
						<input type="checkbox" class="accent-blue-500" bind:checked={allDay} />
						{$i18n.t('All day')}
					</label>
				</div>
			</div>

			<!-- Location -->
			<div>
				<div class="mb-1 text-xs text-gray-500">{$i18n.t('Location')}</div>
				<input
					class="w-full text-sm bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700"
					placeholder={$i18n.t('Add location')}
					bind:value={location}
				/>
			</div>

			<!-- Reminder -->
			<div>
				<div class="mb-1 text-xs text-gray-500">{$i18n.t('Reminder')}</div>
				<select
					class="w-full text-sm bg-transparent outline-hidden cursor-pointer"
					bind:value={alertMinutes}
				>
					<option value={-1}>{$i18n.t('None')}</option>
					<option value={0}>{$i18n.t('At time of event')}</option>
					<option value={5}>{$i18n.t('5 minutes before')}</option>
					<option value={10}>{$i18n.t('10 minutes before')}</option>
					<option value={15}>{$i18n.t('15 minutes before')}</option>
					<option value={30}>{$i18n.t('30 minutes before')}</option>
					<option value={60}>{$i18n.t('1 hour before')}</option>
				</select>
			</div>

			<!-- Repeat -->
			<div>
				<div class="mb-1 text-xs text-gray-500">{$i18n.t('Repeat')}</div>
				<select
					class="w-full text-sm bg-transparent outline-hidden cursor-pointer"
					bind:value={repeatFrequency}
				>
					<option value="">{$i18n.t('No Repeat')}</option>
					<option value="daily">{$i18n.t('Daily')}</option>
					<option value="weekdays">{$i18n.t('Monday – Friday')}</option>
					<option value="weekly">{$i18n.t('Weekly')}</option>
					<option value="monthly">{$i18n.t('Monthly')}</option>
					<option value="yearly">{$i18n.t('Yearly')}</option>
				</select>
			</div>

			<!-- Description -->
			<div>
				<div class="mb-1 text-xs text-gray-500">{$i18n.t('Description')}</div>
				<textarea
					class="w-full text-sm bg-transparent outline-hidden placeholder:text-gray-300 dark:placeholder:text-gray-700 resize-none min-h-[4rem]"
					placeholder={$i18n.t('Add description')}
					bind:value={description}
					rows="3"
				></textarea>
			</div>
		</div>

		<!-- Bottom toolbar -->
		<div class="flex items-center justify-between px-4 pb-3.5 pt-1 gap-2">
			<div class="flex items-center gap-0.5 flex-1 min-w-0">
				{#if event && !event.meta?.automation_id}
					<button
						class="px-3 py-1 text-xs text-gray-400 hover:text-gray-700 dark:hover:text-gray-200 transition"
						type="button"
						on:click={() => (showDeleteConfirmDialog = true)}
						disabled={loading}
					>
						{$i18n.t('Delete')}
					</button>
				{/if}
			</div>

			<div class="flex items-center gap-2 shrink-0">
				<button
					class="px-3 py-1 text-xs text-gray-500 hover:text-gray-700 dark:hover:text-gray-200 transition"
					type="button"
					on:click={() => (show = false)}
				>
					{$i18n.t('Cancel')}
				</button>
				<button
					class="px-3.5 py-1.5 text-sm bg-black hover:bg-gray-900 text-white dark:bg-white dark:text-black dark:hover:bg-gray-100 transition rounded-full flex items-center gap-2 {loading
						? 'cursor-not-allowed'
						: ''}"
					on:click={submitHandler}
					type="button"
					disabled={loading}
				>
					{event && !event.meta?.automation_id ? $i18n.t('Save') : $i18n.t('Create')}
					{#if loading}
						<span class="shrink-0"><Spinner /></span>
					{/if}
				</button>
			</div>
		</div>
	</div>
</Modal>

<DeleteConfirmDialog
	bind:show={showDeleteConfirmDialog}
	title={$i18n.t('Delete Event')}
	message={$i18n.t('This action cannot be undone. Do you wish to continue?')}
	on:confirm={deleteHandler}
/>
