import { Outlet, createFileRoute } from "@tanstack/react-router"
import { useState, useId, useRef, useEffect } from "react"
import { BadRequestError, ApiErrorCode } from "~/api"
import { useCreateBookmark, useDeleteBookmark } from "~/bookmark/api"
import { Button } from "~/components/button"
import { Dialog, DialogTitle, DialogBody, DialogActionRow } from "~/components/dialog"
import { FormField } from "~/components/form-field"
import { LoadingSpinner } from "~/components/loading-spinner"
import { Message, MessageVariant } from "~/components/message"
import { useMnemonics } from "~/hooks/use-mnemonics"
import { useBookmarkPageStore, ActiveDialog, LayoutMode } from "./bookmarks/-store"

export const Route = createFileRoute("/bookmarks")({
	component: RouteComponent,
})

function RouteComponent() {
	const setLayoutMode = useBookmarkPageStore((state) => state.setLayoutMode)

	useEffect(() => {
		function mediaQueryListener(this: MediaQueryList) {
			console.log(this.matches)
			if (this.matches) {
				setLayoutMode(LayoutMode.SideBySide)
			} else {
				setLayoutMode(LayoutMode.Popup)
			}
		}

		const q = window.matchMedia("(width >= 64rem)")
		q.addEventListener("change", mediaQueryListener)

		mediaQueryListener.call(q)

		return () => {
			q.removeEventListener("change", mediaQueryListener)
		}
	}, [setLayoutMode])

	return (
		<div className="relative">
			<Outlet />
			<PageDialog />
		</div>
	)
}
function PageDialog() {
	const dialog = useBookmarkPageStore((state) => state.activeDialog)
	switch (dialog) {
		case ActiveDialog.None:
			return null
		case ActiveDialog.AddBookmark:
			return <AddBookmarkDialog />
		case ActiveDialog.DeleteBookmark:
			return <DeleteBookmarkDialog />
	}
}

function AddBookmarkDialog() {
	const [isWebsiteUnreachable, setIsWebsiteUnreachable] = useState(false)
	const createBookmarkMutation = useCreateBookmark()
	const setActiveDialog = useBookmarkPageStore((state) => state.setActiveDialog)
	const formId = useId()
	const linkInputRef = useRef<HTMLInputElement | null>(null)

	useMnemonics(
		{
			c: () => {
				if (linkInputRef.current !== document.activeElement) {
					cancel()
				}
			},
			Escape: () => {
				linkInputRef.current?.blur()
			},
		},
		{ ignore: () => false },
	)

	useEffect(() => {
		setTimeout(() => {
			if (linkInputRef.current) {
				linkInputRef.current.focus()
			}
		}, 0)
	}, [])

	async function onSubmit(event: React.FormEvent<HTMLFormElement>) {
		event.preventDefault()

		const formData = new FormData(event.currentTarget)
		const url = formData.get("link")
		if (url && typeof url === "string") {
			try {
				await createBookmarkMutation.mutateAsync({ url, force: isWebsiteUnreachable })
				setActiveDialog(ActiveDialog.None)
			} catch (error) {
				if (error instanceof BadRequestError && error.code === ApiErrorCode.WebsiteUnreachable) {
					setIsWebsiteUnreachable(true)
				} else {
					setIsWebsiteUnreachable(false)
				}
			}
		}
	}

	function cancel() {
		setActiveDialog(ActiveDialog.None)
	}

	function message() {
		if (createBookmarkMutation.isPending) {
			return (
				<p>
					Loading <LoadingSpinner />
				</p>
			)
		}
		if (isWebsiteUnreachable) {
			return (
				<Message variant={MessageVariant.Warning} className="px-4">
					The link does not seem to be reachable. Click "SAVE" to save anyways.
				</Message>
			)
		}
		if (createBookmarkMutation.status === "error") {
			return (
				<Message variant={MessageVariant.Error} className="px-4">
					An error occurred when saving bookmark
				</Message>
			)
		}
		return null
	}

	return (
		<Dialog>
			<DialogTitle>NEW BOOKMARK</DialogTitle>
			<DialogBody>
				{message()}
				<form id={formId} className="px-8" onSubmit={onSubmit}>
					<FormField
						ref={linkInputRef}
						type="text"
						name="link"
						label="LINK"
						className="w-full"
						labelClassName="bg-stone-300 dark:bg-stone-800"
					/>
				</form>
			</DialogBody>
			<DialogActionRow>
				<Button type="submit" disabled={createBookmarkMutation.isPending} form={formId}>
					SAVE
				</Button>
				<Button type="button" disabled={createBookmarkMutation.isPending} onClick={cancel}>
					<span className="underline">C</span>ANCEL
				</Button>
			</DialogActionRow>
		</Dialog>
	)
}

function DeleteBookmarkDialog() {
	// biome-ignore lint/style/noNonNullAssertion: this cannot be null when delete bookmark dialog is visible
	const bookmark = useBookmarkPageStore((state) => state.bookmarkToBeDeleted!)
	const setActiveDialog = useBookmarkPageStore((state) => state.setActiveDialog)
	const markBookmarkForDeletion = useBookmarkPageStore((state) => state.markBookmarkForDeletion)
	const deleteBookmarkMutation = useDeleteBookmark()

	useMnemonics(
		{
			y: proceed,
			n: cancel,
		},
		{ ignore: () => false },
	)

	async function proceed() {
		try {
			await deleteBookmarkMutation.mutateAsync({ bookmark })
			setActiveDialog(ActiveDialog.None)
			markBookmarkForDeletion(null)
		} catch (error) {
			console.error(error)
		}
	}

	function cancel() {
		setActiveDialog(ActiveDialog.None)
		markBookmarkForDeletion(null)
	}

	function body() {
		switch (deleteBookmarkMutation.status) {
			case "pending":
				return (
					<p>
						Deleting <LoadingSpinner />
					</p>
				)
			case "idle":
				return (
					<p>
						The bookmark titled:
						<br />
						<br />
						<strong>
							<em>"{bookmark.title}"</em>
						</strong>
						<br />
						<br />
						will be deleted. Proceed?
					</p>
				)
			case "error":
				return <p className="text-red-500">Failed to delete the bookmark!</p>
		}
	}

	function title() {
		switch (deleteBookmarkMutation.status) {
			case "pending":
				return "PLEASE WAIT"
			case "idle":
				return "CONFIRM"
			case "error":
				return "ERROR OCCURRED"
		}
	}

	return (
		<Dialog>
			<DialogTitle>{title()}</DialogTitle>
			<DialogBody>{body()}</DialogBody>
			<DialogActionRow>
				<Button disabled={deleteBookmarkMutation.isPending} onClick={proceed}>
					{deleteBookmarkMutation.isError ? "Retry" : "Proceed"} (y)
				</Button>
				<Button disabled={deleteBookmarkMutation.isPending} onClick={cancel}>
					Cancel (n)
				</Button>
			</DialogActionRow>
		</Dialog>
	)
}
