import type { Bookmark } from "@markone/core"
import { createFileRoute, useNavigate } from "@tanstack/react-router"
import clsx from "clsx"
import { atom, useAtom } from "jotai"
import { useCallback, useEffect, useRef } from "react"
import { fetchApi, useAuthenticatedQuery } from "~/api"
import { useBookmark } from "~/bookmark/api"
import { Button, LinkButton } from "~/components/button"
import { LoadingSpinner } from "~/components/loading-spinner"
import { useMnemonics } from "~/hooks/use-mnemonics"
import { ActionBar } from "./-action-bar"
import { BookmarkList } from "./-bookmark-list"
import { DialogKind, LayoutMode, useBookmarkPageStore } from "./-store"

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

const actionBarHeight = atom(0)
const setActionBarHeight = atom(null, (_, set, update: number) => {
	set(actionBarHeight, update)
})
const titleBarHeight = atom(0)
const setTitleBarHeight = atom(null, (_, set, update: number) => {
	set(titleBarHeight, update)
})

function RouteComponent() {
	return (
		<Main>
			<BookmarkListSidebar />
			<BookmarkPreviewContainer>
				<BookmarkPreview />
				<BookmarkPreviewTitleBar />
				<BookmarkPreviewActionBar />
			</BookmarkPreviewContainer>
		</Main>
	)
}

function Main({ children }: React.PropsWithChildren) {
	const layoutMode = useBookmarkPageStore((state) => state.layoutMode)
	return (
		<main className={clsx("w-full h-full grid", layoutMode === LayoutMode.SideBySide ? "grid-cols-4" : "grid-cols-1")}>
			{children}
		</main>
	)
}

function BookmarkPreviewContainer({ children }: React.PropsWithChildren) {
	const layoutMode = useBookmarkPageStore((state) => state.layoutMode)

	return (
		<div
			className={clsx(
				"h-screen border-l border-stone-700 dark:border-stone-300 flex dark:bg-stone-900",
				layoutMode === LayoutMode.Popup ? "absolute top-0 left-0 right-0 bottom-0 border-l-0" : "relative col-span-3",
			)}
		>
			{children}
		</div>
	)
}

function BookmarkListSidebar() {
	return (
		<div className="relative flex flex-col py-16 w-full h-screen">
			<header className="mb-4 text-start">
				<h1 className="font-bold text-start mb-4">
					<span className="invisible">&nbsp;&gt;&nbsp;</span>
					YOUR BOOKMARKS
				</h1>
			</header>
			<BookmarkListContainer />
			<BookmarkListActionBar />
		</div>
	)
}

function BookmarkListContainer() {
	const { bookmarkId } = Route.useParams()
	const navigate = useNavigate()
	const { data: bookmarks, status } = useAuthenticatedQuery(["bookmarks"], () =>
		fetchApi("/bookmarks").then((res) => res.json()),
	)
	const handleBookmarkListItemAction = useBookmarkPageStore((state) => state.handleBookmarkListItemAction)

	const onSelectedBookmarkChange = useCallback(
		(bookmark: Bookmark) => {
			navigate({ to: `/bookmarks/${bookmark.id}` })
		},
		[navigate],
	)

	switch (status) {
		case "success":
			return (
				<BookmarkList
					alwaysExpandItem
					bookmarks={bookmarks}
					selectedBookmarkId={bookmarkId}
					onSelectionChange={onSelectedBookmarkChange}
					onItemAction={handleBookmarkListItemAction}
				/>
			)

		case "pending":
			return (
				<p>
					Loading <LoadingSpinner />
				</p>
			)

		case "error":
			return <p>error loading bookmarks</p>
	}
}

function BookmarkListActionBar() {
	const setActiveDialog = useBookmarkPageStore((state) => state.setActiveDialog)

	function addBookmark() {
		setActiveDialog({ kind: DialogKind.AddBookmark })
	}

	useMnemonics(
		{
			a: addBookmark,
		},
		{ ignore: useCallback(() => useBookmarkPageStore.getState().dialog.kind !== DialogKind.None, []) },
	)

	return (
		<ActionBar className="absolute bottom-0 left-0 right-0">
			<Button onClick={addBookmark}>
				<span className="underline">A</span>DD
			</Button>
		</ActionBar>
	)
}

function BookmarkPreview() {
	const { bookmarkId } = Route.useParams()
	const { data: previewHtml, status: previewQueryStatus } = useAuthenticatedQuery(
		["bookmarks", `${bookmarkId}.html`],
		() =>
			fetchApi(`/bookmarks/${bookmarkId}`, {
				headers: {
					Accept: "text/html",
				},
			}).then((res) => res.text()),
	)
	const { data: bookmark, status: bookmarkQueryStatus } = useBookmark(bookmarkId)
	const [_titleBarHeight] = useAtom(titleBarHeight)
	const [_actionBarHeight] = useAtom(actionBarHeight)
	const navigate = useNavigate()

	function attachKeyListenerToIFrame(event: React.SyntheticEvent<HTMLIFrameElement, Event>) {
		if (event.currentTarget.contentDocument) {
			event.currentTarget.contentDocument.addEventListener("keydown", (keyEvent) => {
				switch (keyEvent.key) {
					case "c":
						navigate({ to: "/bookmarks", replace: true })
						break
					case "o":
						if (bookmark) {
							window.open(bookmark.url, "_blank")?.focus()
						}
						break
					default:
						break
				}
			})
		}
	}

	if (previewQueryStatus === "error") {
		return (
			<div className="w-full h-full flex items-center justify-center">
				<p>Preview not available</p>
			</div>
		)
	}

	if (previewQueryStatus === "success" && bookmarkQueryStatus === "success") {
		return (
			<iframe
				title={bookmark.id}
				className="w-full h-full"
				style={{ paddingTop: _titleBarHeight, paddingBottom: _actionBarHeight }}
				srcDoc={previewHtml}
				onLoad={attachKeyListenerToIFrame}
			/>
		)
	}

	if (previewQueryStatus === "pending" || bookmarkQueryStatus === "pending") {
		return (
			<div className="w-full h-full flex items-center justify-center">
				<p className="mx-0 my-auto">
					Loading <LoadingSpinner />
				</p>
			</div>
		)
	}

	return null
}

function BookmarkPreviewTitleBar() {
	const { bookmarkId } = Route.useParams()
	const layoutMode = useBookmarkPageStore((state) => state.layoutMode)
	const { data: bookmark, status } = useBookmark(bookmarkId)
	const [, _setTitleBarHeight] = useAtom(setTitleBarHeight)
	const headerRef = useRef<HTMLElement | null>(null)
	const isHidden = status !== "success" || layoutMode !== LayoutMode.Popup

	useEffect(() => {
		if (headerRef.current) {
			_setTitleBarHeight(headerRef.current.clientHeight)
		} else {
			_setTitleBarHeight(0)
		}
	})

	if (isHidden) {
		return null
	}

	const url = new URL(bookmark.url)

	return (
		<header
			ref={headerRef}
			className="absolute top-0 left-0 right-0 flex flex-col items-center bg-stone-200 dark:bg-stone-900 px-2 py-1 border-b-1 border-stone-700 dark:border-stone-300"
		>
			<h1 className="text-center">{bookmark.title}</h1>
			<h2 className="text-center opacity-80 text-sm">{url.host}</h2>
		</header>
	)
}

function BookmarkPreviewActionBar() {
	const { bookmarkId } = Route.useParams()
	const navigate = useNavigate()
	const { data: bookmark, status } = useBookmark(bookmarkId)
	const linkRef = useRef<HTMLAnchorElement | null>(null)
	const [, _setActionBarHeight] = useAtom(setActionBarHeight)

	useMnemonics(
		{
			c: close,
			o: openLink,
		},
		{ ignore: () => false },
	)

	function close() {
		navigate({ to: "/bookmarks", replace: true })
	}

	function openLink() {
		if (bookmark) {
			window.open(bookmark.url, "_blank")?.focus()
		}
	}

	if (status !== "success") {
		return null
	}

	return (
		<ActionBar
			ref={(el) => {
				if (el) {
					_setActionBarHeight(el.clientHeight)
				}
			}}
			className="absolute bottom-0 left-0 right-0"
		>
			<LinkButton ref={linkRef} to={bookmark.url}>
				<span className="underline">O</span>PEN LINK
			</LinkButton>
			<Button onClick={close}>
				<span className="underline">C</span>LOSE
			</Button>
		</ActionBar>
	)
}
