<script lang="ts">
	import { onMount, getContext } from "svelte";
	import { toast } from "svelte-sonner";
	import { goto } from "$app/navigation";

	import dayjs from "dayjs";
	import relativeTime from "dayjs/plugin/relativeTime";
	import localizedFormat from "dayjs/plugin/localizedFormat";

	import { REXPRO_NAME, showSidebar } from "$lib/stores";

	import {
		updateAutomationById,
		toggleAutomationById,
		runAutomationById,
		deleteAutomationById,
		getAutomationRuns,
		type AutomationForm,
		type AutomationResponse,
		type AutomationRunModel,
	} from "$lib/apis/automations";

	import Spinner from "$lib/components/common/Spinner.svelte";
	import Tooltip from "$lib/components/common/Tooltip.svelte";
	import DeleteConfirmDialog from "$lib/components/common/ConfirmDialog.svelte";
	import GarbageBin from "$lib/components/icons/GarbageBin.svelte";
	import ChevronLeft from "$lib/components/icons/ChevronLeft.svelte";

	import ScheduleDropdown from "$lib/components/automations/ScheduleDropdown.svelte";
	import ModelDropdown from "$lib/components/automations/ModelDropdown.svelte";

	dayjs.extend(relativeTime);
	dayjs.extend(localizedFormat);

	const i18n = getContext("i18n");

	export let automation: AutomationResponse;

	let name = "";
	let prompt = "";
	let model_id = "";
	let is_active = true;

	let loading = false;
	let saving = false;
	let showDeleteConfirm = false;

	let runs: AutomationRunModel[] = [];
	let runsLoading = false;
	let hasMoreRuns = true;
	let runsPage = 0;
	let isDirty = false;

	let scheduleDropdown: ScheduleDropdown;

	const formatRunTime = (ts: number): string => {
		const now = Date.now();
		const diff = now - ts / 1_000_000;

		const seconds = Math.floor(diff / 1000);
		const minutes = Math.floor(seconds / 60);
		const hours = Math.floor(minutes / 60);
		const days = Math.floor(hours / 24);
		const weeks = Math.floor(days / 7);
		const years = Math.floor(days / 365);

		if (years > 0)
			return $i18n.t("{{COUNT}}y", { COUNT: years, context: "time_ago" });
		if (weeks > 0)
			return $i18n.t("{{COUNT}}w", { COUNT: weeks, context: "time_ago" });
		if (days > 0)
			return $i18n.t("{{COUNT}}d", { COUNT: days, context: "time_ago" });
		if (hours > 0)
			return $i18n.t("{{COUNT}}h", { COUNT: hours, context: "time_ago" });
		if (minutes > 0)
			return $i18n.t("{{COUNT}}m", {
				COUNT: minutes,
				context: "time_ago",
			});
		return $i18n.t("1m", { context: "time_ago" });
	};

	const formatNextRun = (ts: number | null): string => {
		if (!ts) return $i18n.t("Not scheduled");
		const d = dayjs(ts / 1_000_000);
		if (d.isSame(dayjs(), "day"))
			return `${$i18n.t("Today at")} ${d.format("LT")}`;
		return d.format("L LT");
	};

	const saveHandler = async () => {
		if (!name.trim() || !prompt.trim() || !model_id.trim()) {
			toast.error($i18n.t("Name, prompt, and model are required"));
			return;
		}
		saving = true;
		try {
			const form: AutomationForm = {
				name: name.trim(),
				data: {
					prompt: prompt.trim(),
					model_id: model_id.trim(),
					rrule: scheduleDropdown.buildRrule(),
				},
				is_active,
			};
			const updated = await updateAutomationById(
				localStorage.token,
				automation.id,
				form,
			);
			if (updated) {
				automation = updated;
				isDirty = false;
				toast.success($i18n.t("Automation updated"));
			}
		} catch (e: any) {
			toast.error(e?.detail ?? `${e}` ?? "Failed to save");
		} finally {
			saving = false;
		}
	};

	const toggleHandler = async () => {
		const res = await toggleAutomationById(
			localStorage.token,
			automation.id,
		).catch((err) => {
			toast.error(`${err}`);
			return null;
		});
		if (res) {
			is_active = res.is_active;
			automation = res;
		}
	};

	const runNowHandler = async () => {
		loading = true;
		const res = await runAutomationById(
			localStorage.token,
			automation.id,
		).catch((err) => {
			toast.error(`${err}`);
			return null;
		});
		if (res) {
			toast.success($i18n.t("Automation triggered"));
			setTimeout(() => loadRuns(false), 2000);
		}
		loading = false;
	};

	const deleteHandler = async () => {
		const res = await deleteAutomationById(
			localStorage.token,
			automation.id,
		).catch((err) => {
			toast.error(`${err}`);
			return null;
		});
		if (res) {
			toast.success(
				$i18n.t(`Deleted {{name}}`, { name: automation.name }),
			);
			goto("/automations");
		}
	};

	const loadRuns = async (loadMore = false) => {
		if (runsLoading || (!hasMoreRuns && loadMore)) return;

		runsLoading = true;

		if (!loadMore) {
			runsPage = 0;
			hasMoreRuns = true;
		}

		try {
			const fetchedRuns =
				(await getAutomationRuns(
					localStorage.token,
					automation.id,
					runsPage * 50,
					50,
				)) ?? [];
			if (loadMore) {
				runs = [...runs, ...fetchedRuns];
			} else {
				runs = fetchedRuns;
			}

			if (fetchedRuns.length < 50) {
				hasMoreRuns = false;
			}
			runsPage++;
		} catch {
			if (!loadMore) runs = [];
		}
		runsLoading = false;
	};

	const markDirty = () => {
		isDirty = true;
	};

	const onScroll = (e: Event) => {
		const target = e.target as HTMLElement;
		if (
			target.scrollTop + target.clientHeight >=
			target.scrollHeight - 50
		) {
			if (!runsLoading && hasMoreRuns) {
				loadRuns(true);
			}
		}
	};

	onMount(async () => {
		name = automation.name;
		prompt = automation.data.prompt;
		model_id = automation.data.model_id;
		is_active = automation.is_active;

		if (scheduleDropdown) {
			scheduleDropdown.parseRrule(automation.data.rrule);
		}

		await loadRuns();
	});
</script>

<svelte:head>
	<title>{name || $i18n.t("Automation")} • {$REXPRO_NAME}</title>
</svelte:head>

<DeleteConfirmDialog
	bind:show={showDeleteConfirm}
	title={$i18n.t("Delete automation?")}
	on:confirm={deleteHandler}
>
	<div class="text-sm text-gray-500 truncate">
		{$i18n.t("This will delete")} <span class="">{automation.name}</span>.
	</div>
</DeleteConfirmDialog>

<div
	class="flex flex-col w-full h-screen max-h-[100dvh] transition-width duration-200 ease-in-out {$showSidebar
		? 'md:max-w-[calc(100%-var(--sidebar-width))]'
		: ''} max-w-full"
>
	<div class="flex-1 max-h-full flex flex-col pt-3 pb-1 px-3 md:px-[18px]">
		<!-- Header Segment (Shrink-0 so it doesn't compress) -->
		<div class="flex items-start justify-between gap-4 shrink-0 mb-0.5">
			<div class="flex-1 min-w-0">
				<div class="flex items-center gap-1.5 mb-1.5">
					<Tooltip content={$i18n.t("Back")}>
						<button
							class="text-sm p-1.5 hover:bg-black/5 dark:hover:bg-white/5 rounded-lg transition"
							aria-label={$i18n.t("Back")}
							on:click={() => goto("/automations")}
							type="button"
						>
							<ChevronLeft strokeWidth="2.5" />
						</button>
					</Tooltip>
					<input
						class="text-2xl w-full bg-transparent outline-hidden"
						placeholder={$i18n.t("Automation Name")}
						bind:value={name}
						on:input={markDirty}
					/>
				</div>
			</div>

			<div class="flex items-center gap-2 shrink-0">
				<Tooltip content={$i18n.t("Delete")}>
					<button
						class="p-2 rounded-full bg-transparent hover:bg-gray-50 dark:hover:bg-gray-850 text-gray-500 hover:text-black dark:hover:text-white transition"
						on:click={() => (showDeleteConfirm = true)}
						type="button"
					>
						<GarbageBin />
					</button>
				</Tooltip>

				{#if isDirty}
					<button
						class="px-3 py-1 text-sm bg-black text-white dark:bg-white dark:text-black rounded-full hover:opacity-90 transition flex items-center gap-1.5"
						on:click={saveHandler}
						disabled={saving}
						type="button"
					>
						{$i18n.t("Save")}
						{#if saving}
							<Spinner className="size-3" />
						{/if}
					</button>
				{/if}

				<button
					class="px-2.5 py-1 text-sm border border-gray-200 dark:border-gray-800 hover:bg-gray-50 dark:hover:bg-gray-850 transition rounded-full flex items-center gap-1.5"
					on:click={runNowHandler}
					type="button"
					disabled={loading}
				>
					<svg
						xmlns="http://www.w3.org/2000/svg"
						viewBox="0 0 20 20"
						fill="currentColor"
						class="size-3.5"
					>
						<path
							d="M6.3 2.84A1.5 1.5 0 0 0 4 4.11v11.78a1.5 1.5 0 0 0 2.3 1.27l9.344-5.891a1.5 1.5 0 0 0 0-2.538L6.3 2.841Z"
						/>
					</svg>
					<div class="hidden md:block">{$i18n.t("Run now")}</div>
					{#if loading}
						<Spinner className="size-3" />
					{/if}
				</button>
			</div>
		</div>

		<!-- Content Segment: Independent Scrolling Columns based on PromptEditor -->
		<div
			class="flex flex-col md:flex-row gap-4 flex-1 overflow-hidden pb-2 px-1"
		>
			<!-- Main Input Column -->
			<div class="flex-1 flex flex-col min-h-0 overflow-hidden">
				<div
					class="flex items-center justify-between mb-2 shrink-0 px-1"
				>
					<div class="text-gray-500 text-xs">
						{$i18n.t("Instructions")}
					</div>
				</div>
				<div class="relative flex-1 min-h-0">
					<div
						class="bg-gray-50 dark:bg-gray-900 rounded-2xl p-4 border border-gray-100/50 dark:border-gray-850/50 h-full"
					>
						<textarea
							class="w-full h-full text-sm bg-transparent outline-hidden resize-none placeholder:text-gray-300 dark:placeholder:text-gray-700"
							bind:value={prompt}
							on:input={markDirty}
							placeholder={$i18n.t(
								"Enter the prompt instructions for this automation...",
							)}
						/>
					</div>
				</div>
			</div>

			<!-- Sidebar Configuration Column -->
			<div
				class="hidden md:flex w-full md:w-66 shrink-0 overflow-y-auto px-1 flex-col gap-5"
			>
				<div>
					<div class="text-gray-500 text-xs mb-3">
						{$i18n.t("Configuration")}
					</div>
					<div class="space-y-1">
						<!-- Schedule -->
						<div class="flex items-center justify-between text-xs">
							<span class="text-gray-600 dark:text-gray-400"
								>{$i18n.t("Repeats")}</span
							>
							<ScheduleDropdown
								bind:this={scheduleDropdown}
								side="bottom"
								align="end"
								onChange={markDirty}
							/>
						</div>

						<!-- Model -->
						<div class="flex items-center justify-between text-xs">
							<span class="text-gray-600 dark:text-gray-400"
								>{$i18n.t("Model")}</span
							>
							<ModelDropdown
								bind:model_id
								side="bottom"
								align="end"
								onChange={markDirty}
							/>
						</div>
					</div>
				</div>

				<!-- Status section -->
				<div>
					<div class="text-gray-500 text-xs mb-3">
						{$i18n.t("Status")}
					</div>
					<div class="space-y-2.5">
						<div class="flex items-center justify-between text-xs">
							<span class="text-gray-600 dark:text-gray-400"
								>{$i18n.t("State")}</span
							>
							<span
								class="flex items-center gap-1.5 text-xs {is_active
									? 'text-emerald-700 dark:text-emerald-400'
									: 'text-gray-600 dark:text-gray-400'}"
							>
								<span
									class="inline-block size-1.5 rounded-full {is_active
										? 'bg-emerald-500'
										: 'bg-gray-400'}"
								></span>
								{is_active
									? $i18n.t("Active")
									: $i18n.t("Paused")}
							</span>
						</div>

						<div class="flex items-center justify-between text-xs">
							<span class="text-gray-600 dark:text-gray-400"
								>{$i18n.t("Next run")}</span
							>
							<span class=" text-gray-700 dark:text-gray-300"
								>{formatNextRun(
									automation.next_runs?.[0] ??
										automation.next_run_at,
								)}</span
							>
						</div>

						<div class="flex items-center justify-between text-xs">
							<span class="text-gray-600 dark:text-gray-400"
								>{$i18n.t("Last ran")}</span
							>
							<span class=" text-gray-700 dark:text-gray-300"
								>{automation.last_run_at
									? formatNextRun(automation.last_run_at)
									: $i18n.t("Never")}</span
							>
						</div>
					</div>
				</div>

				<div class="flex-1 flex flex-col min-h-0 -mx-1">
					<div class="text-gray-500 text-xs mb-2 mx-1 shrink-0">
						{$i18n.t("Execution Logs")}
					</div>
					<div
						class="flex-1 overflow-y-auto scrollbar-hidden w-full"
						on:scroll={onScroll}
					>
						{#if runsLoading && runs.length === 0}
							<div class="flex justify-center py-4">
								<Spinner className="size-4" />
							</div>
						{:else if runs.length === 0}
							<div
								class="text-xs text-gray-400 py-4 tabular-nums"
							>
								{$i18n.t("No execution logs available yet")}
							</div>
						{:else}
							<div class="space-y-0.5 w-full">
								{#each runs as run (run.id)}
									<button
										class="w-full text-left flex items-center gap-2.5 px-2.5 py-1.5 rounded-xl hover:bg-gray-100/80 dark:hover:bg-gray-850/80 transition-colors {run.chat_id
											? 'cursor-pointer'
											: 'cursor-default'}"
										on:click={() => {
											if (run.chat_id)
												goto(`/c/${run.chat_id}`);
										}}
										type="button"
									>
										<div
											class="shrink-0 flex items-center justify-center"
										>
											{#if run.status === "success"}
												<svg
													xmlns="http://www.w3.org/2000/svg"
													viewBox="0 0 20 20"
													fill="currentColor"
													class="size-3 text-emerald-500"
													><path
														fill-rule="evenodd"
														d="M10 18a8 8 0 100-16 8 8 0 000 16zm3.857-9.809a.75.75 0 00-1.214-.882l-3.483 4.79-1.88-1.88a.75.75 0 10-1.06 1.061l2.5 2.5a.75.75 0 001.137-.089l4-5.5z"
														clip-rule="evenodd"
													/></svg
												>
											{:else if run.status === "error"}
												<svg
													xmlns="http://www.w3.org/2000/svg"
													viewBox="0 0 20 20"
													fill="currentColor"
													class="size-3 text-red-500"
													><path
														fill-rule="evenodd"
														d="M10 18a8 8 0 100-16 8 8 0 000 16zM8.28 7.22a.75.75 0 00-1.06 1.06L8.94 10l-1.72 1.72a.75.75 0 101.06 1.06L10 11.06l1.72 1.72a.75.75 0 101.06-1.06L11.06 10l1.72-1.72a.75.75 0 00-1.06-1.06L10 8.94 8.28 7.22z"
														clip-rule="evenodd"
													/></svg
												>
											{:else}
												<svg
													xmlns="http://www.w3.org/2000/svg"
													viewBox="0 0 20 20"
													fill="currentColor"
													class="size-3 text-blue-500"
													><path
														d="M10 18a8 8 0 100-16 8 8 0 000 16zm.75-13a.75.75 0 00-1.5 0v5c0 .414.336.75.75.75h4a.75.75 0 000-1.5h-3.25V5z"
													/></svg
												>
											{/if}
										</div>
										<div class="flex-1 min-w-0">
											<div
												class="text-xs text-gray-800 dark:text-gray-200 truncate"
											>
												{automation.name}
											</div>
										</div>
										<span
											class="shrink-0 text-[10px] text-gray-500 font-mono"
											>{formatRunTime(
												run.created_at,
											)}</span
										>
									</button>
								{/each}

								{#if runsLoading && runs.length > 0}
									<div class="flex justify-center py-4">
										<Spinner className="size-4" />
									</div>
								{/if}
							</div>
						{/if}
					</div>
				</div>
			</div>
		</div>
	</div>
</div>
