"use client"

import React, { useState, useEffect, useRef } from "react"
import { useForm } from "react-hook-form"
import { zodResolver } from "@hookform/resolvers/zod"
import { useDebounce } from "react-use"
import { toast } from "sonner"
import Image from "next/image"
import { z } from "zod"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Textarea } from "@/components/ui/textarea"
import { Form, FormField, FormItem, FormLabel, FormControl } from "@/components/ui/form"
import { BoxIcon, PlusIcon, Trash2Icon, PieChartIcon, Bookmark, GraduationCap, Check } from "lucide-react"
import { cn, ensureUrlProtocol, generateUniqueSlug, isUrl as LibIsUrl } from "@/lib/utils"
import { useAccount, useCoState } from "@/lib/providers/jazz-provider"
import { LinkMetadata, PersonalLink } from "@/lib/schema/personal-link"
import { createLinkSchema } from "./schema"
import { TopicSelector } from "./partial/topic-section"
import { useAtom } from "jotai"
import { linkEditIdAtom, linkShowCreateAtom } from "@/store/link"
import {
	DropdownMenu,
	DropdownMenuContent,
	DropdownMenuItem,
	DropdownMenuLabel,
	DropdownMenuTrigger
} from "@/components/ui/dropdown-menu"
import { useKey } from "react-use"

export type LinkFormValues = z.infer<typeof createLinkSchema>

const DEFAULT_FORM_VALUES: Partial<LinkFormValues> = {
	title: "",
	description: "",
	topic: "",
	isLink: false,
	meta: null
}

const LinkManage: React.FC = () => {
	const [showCreate, setShowCreate] = useAtom(linkShowCreateAtom)
	const [, setEditId] = useAtom(linkEditIdAtom)
	const formRef = useRef<HTMLFormElement>(null)
	const buttonRef = useRef<HTMLButtonElement>(null)

	const toggleForm = (event: React.MouseEvent) => {
		event.stopPropagation()
		setShowCreate(prev => !prev)
	}

	useEffect(() => {
		if (!showCreate) {
			formRef.current?.reset()
			setEditId(null)
		}
	}, [showCreate, setEditId])

	useEffect(() => {
		const handleOutsideClick = (event: MouseEvent) => {
			if (
				formRef.current &&
				!formRef.current.contains(event.target as Node) &&
				buttonRef.current &&
				!buttonRef.current.contains(event.target as Node)
			) {
				setShowCreate(false)
			}
		}

		if (showCreate) {
			document.addEventListener("mousedown", handleOutsideClick)
		}

		return () => {
			document.removeEventListener("mousedown", handleOutsideClick)
		}
	}, [showCreate, setShowCreate])

	useKey("Escape", () => {
		setShowCreate(false)
	})

	return (
		<>
			{showCreate && (
				<div className="z-50">
					<LinkForm ref={formRef} onSuccess={() => setShowCreate(false)} onCancel={() => setShowCreate(false)} />
				</div>
			)}
			<CreateButton ref={buttonRef} onClick={toggleForm} isOpen={showCreate} />
		</>
	)
}

const CreateButton = React.forwardRef<
	HTMLButtonElement,
	{
		onClick: (event: React.MouseEvent) => void
		isOpen: boolean
	}
>(({ onClick, isOpen }, ref) => (
	<Button
		ref={ref}
		className={cn(
			"absolute bottom-4 right-4 size-12 rounded-full bg-[#274079] p-0 text-white transition-transform hover:bg-[#274079]/90",
			{ "rotate-45 transform": isOpen }
		)}
		onClick={onClick}
	>
		<PlusIcon className="size-6" />
	</Button>
))

CreateButton.displayName = "CreateButton"

interface LinkFormProps extends React.ComponentPropsWithoutRef<"form"> {
	onSuccess?: () => void
	onCancel?: () => void
	personalLink?: PersonalLink
}

const LinkForm = React.forwardRef<HTMLFormElement, LinkFormProps>(({ onSuccess, onCancel, personalLink }, ref) => {
	const selectedLink = useCoState(PersonalLink, personalLink?.id)
	const [isFetching, setIsFetching] = useState(false)
	const { me } = useAccount()
	const form = useForm<LinkFormValues>({
		resolver: zodResolver(createLinkSchema),
		defaultValues: DEFAULT_FORM_VALUES
	})

	const title = form.watch("title")
	const [inputValue, setInputValue] = useState("")
	const [originalLink, setOriginalLink] = useState<string>("")
	const [invalidLink, setInvalidLink] = useState(false)
	const [showLinkStatus, setShowLinkStatus] = useState(false)
	const [debouncedText, setDebouncedText] = useState<string>("")
	useDebounce(() => setDebouncedText(title), 300, [title])

	const [showStatusOptions, setShowStatusOptions] = useState(false)
	const [selectedStatus, setSelectedStatus] = useState<string | null>(null)

	const statusOptions = [
		{
			text: "To Learn",
			icon: <Bookmark size={16} />,
			color: "text-white/70"
		},
		{
			text: "Learning",
			icon: <GraduationCap size={16} />,
			color: "text-[#D29752]"
		},
		{ text: "Learned", icon: <Check size={16} />, color: "text-[#708F51]" }
	]

	const statusSelect = (status: string) => {
		setSelectedStatus(status === selectedStatus ? null : status)
		setShowStatusOptions(false)
	}

	useEffect(() => {
		if (selectedLink) {
			form.setValue("title", selectedLink.title)
			form.setValue("description", selectedLink.description ?? "")
			form.setValue("isLink", selectedLink.isLink)
			form.setValue("meta", selectedLink.meta)
		}
	}, [selectedLink, form])

	const changeInput = (e: React.ChangeEvent<HTMLInputElement>) => {
		const value = e.target.value
		setInputValue(value)
		setShowLinkStatus(false)
		setInvalidLink(false)
	}

	const pressEnter = (e: React.KeyboardEvent<HTMLInputElement>) => {
		if (e.key === "Enter") {
			e.preventDefault()
			const trimmedValue = inputValue.trim().toLowerCase()
			if (LibIsUrl(trimmedValue)) {
				form.setValue("title", trimmedValue)
				setShowLinkStatus(true)
				setInvalidLink(false)
			} else {
				setInvalidLink(true)
				setShowLinkStatus(true)
			}
		}
	}

	useEffect(() => {
		const fetchMetadata = async (url: string) => {
			setIsFetching(true)
			try {
				const res = await fetch(`/api/metadata?url=${encodeURIComponent(url)}`, { cache: "force-cache" })
				if (!res.ok) throw new Error("Failed to fetch metadata")
				const data = await res.json()
				form.setValue("isLink", true)
				form.setValue("meta", data)
				form.setValue("title", data.title)
				form.setValue("description", data.description)
				setOriginalLink(url)
			} catch (err) {
				form.setValue("isLink", false)
				form.setValue("meta", null)
				form.setValue("title", debouncedText)
				form.setValue("description", "")
				setOriginalLink("")
			} finally {
				setIsFetching(false)
			}
		}
		if (showLinkStatus && !invalidLink && LibIsUrl(form.getValues("title").toLowerCase())) {
			fetchMetadata(ensureUrlProtocol(form.getValues("title").toLowerCase()))
		}
	}, [showLinkStatus, invalidLink, form])

	const onSubmit = (values: LinkFormValues) => {
		if (isFetching) return

		try {
			let linkMetadata: LinkMetadata | undefined

			const personalLinks = me.root?.personalLinks?.toJSON() || []
			const slug = generateUniqueSlug(personalLinks, values.title)

			if (values.isLink && values.meta) {
				linkMetadata = LinkMetadata.create(values.meta, { owner: me._owner })
			}

			if (selectedLink) {
				selectedLink.title = values.title
				selectedLink.slug = slug
				selectedLink.description = values.description ?? ""
				selectedLink.isLink = values.isLink

				if (values.isLink && values.meta) {
					linkMetadata = LinkMetadata.create(values.meta, { owner: me._owner })
				}
			} else {
				const newPersonalLink = PersonalLink.create(
					{
						title: values.title,
						slug,
						description: values.description,
						sequence: me.root?.personalLinks?.length || 1,
						completed: false,
						isLink: values.isLink,
						meta: linkMetadata
						// topic: values.topic
					},
					{ owner: me._owner }
				)

				me.root?.personalLinks?.push(newPersonalLink)
			}

			form.reset(DEFAULT_FORM_VALUES)
			onSuccess?.()
		} catch (error) {
			console.error("Failed to create/update link", error)
			toast.error(personalLink ? "Failed to update link" : "Failed to create link")
		}
	}

	const undoEditing: () => void = () => {
		form.reset(DEFAULT_FORM_VALUES)
		onCancel?.()
	}

	return (
		<div className="p-3 transition-all">
			<div className="rounded-md border bg-muted/50">
				<Form {...form}>
					<form onSubmit={form.handleSubmit(onSubmit)} className="relative min-w-0 flex-1" ref={ref}>
						<div className="flex flex-row p-3">
							<div className="flex flex-auto flex-col gap-1.5">
								<div className="flex flex-row items-start justify-between">
									<div className="flex grow flex-row items-center gap-1.5">
										<Button
											type="button"
											variant="secondary"
											size="icon"
											aria-label="Choose icon"
											className="size-7 text-primary/60"
										>
											{form.watch("isLink") ? (
												<Image
													src={form.watch("meta")?.favicon || ""}
													alt={form.watch("meta")?.title || ""}
													className="size-5 rounded-md"
													width={16}
													height={16}
												/>
											) : (
												<BoxIcon size={16} />
											)}
										</Button>

										<FormField
											control={form.control}
											name="title"
											render={({ field }) => (
												<FormItem className="grow space-y-0">
													<FormLabel className="sr-only">Text</FormLabel>
													<FormControl>
														<Input
															{...field}
															value={inputValue}
															autoComplete="off"
															maxLength={100}
															autoFocus
															placeholder="Paste a link or write a link"
															className={cn(
																"h-6 border-none p-1.5 font-medium placeholder:text-primary/40 focus-visible:outline-none focus-visible:ring-0",
																invalidLink ? "text-red-500" : ""
															)}
															onKeyDown={pressEnter}
															onChange={changeInput}
														/>
													</FormControl>
												</FormItem>
											)}
										/>
										{showLinkStatus && (
											<span className={cn("mr-5 max-w-[200px] truncate text-xs", invalidLink ? "text-red-500" : "")}>
												{invalidLink ? "Allowing links only" : originalLink || ""}
											</span>
										)}
									</div>

									<div className="flex min-w-0 shrink-0 cursor-pointer select-none flex-row">
										<DropdownMenu>
											<DropdownMenuTrigger asChild></DropdownMenuTrigger>
											<DropdownMenuContent align="end">
												<DropdownMenuLabel>Actions</DropdownMenuLabel>
												<DropdownMenuItem className="group">
													<Trash2Icon size={16} className="mr-2 text-destructive group-hover:text-red-500" />
													<span>Delete</span>
												</DropdownMenuItem>
											</DropdownMenuContent>
										</DropdownMenu>
										<div className="relative">
											<Button
												size="icon"
												type="button"
												variant="ghost"
												className="size-7 gap-x-2 text-sm"
												onClick={() => setShowStatusOptions(!showStatusOptions)}
											>
												{selectedStatus ? (
													(() => {
														const option = statusOptions.find(opt => opt.text === selectedStatus)
														return option
															? React.cloneElement(option.icon, {
																	size: 16,
																	className: option.color
																})
															: null
													})()
												) : (
													<PieChartIcon size={16} className="text-primary/60" />
												)}
											</Button>
											{showStatusOptions && (
												<div className="absolute right-0 mt-1 w-40 rounded-md bg-neutral-800 shadow-lg">
													{statusOptions.map(option => (
														<Button
															key={option.text}
															onClick={() => statusSelect(option.text)}
															className={`flex w-full items-center justify-start space-x-2 rounded-md px-3 py-2 text-sm font-medium hover:bg-neutral-700 ${option.color} bg-inherit`}
														>
															{React.cloneElement(option.icon, {
																size: 16,
																className: option.color
															})}
															<span>{option.text}</span>
														</Button>
													))}
												</div>
											)}
										</div>
									</div>
								</div>

								<div className="flex flex-row items-center gap-1.5 pl-8">
									<FormField
										control={form.control}
										name="description"
										render={({ field }) => (
											<FormItem className="grow space-y-0">
												<FormLabel className="sr-only">Description</FormLabel>
												<FormControl>
													<Textarea
														{...field}
														autoComplete="off"
														placeholder="Description (optional)"
														className="min-h-[24px] resize-none overflow-y-auto border-none p-1.5 text-xs font-medium shadow-none placeholder:text-primary/40 focus-visible:outline-none focus-visible:ring-0"
														onInput={e => {
															const target = e.target as HTMLTextAreaElement
															target.style.height = "auto"
															target.style.height = `${target.scrollHeight}px`
														}}
													/>
												</FormControl>
											</FormItem>
										)}
									/>
								</div>
							</div>
						</div>

						<div className="flex flex-auto flex-row items-center justify-between gap-2 rounded-b-md border border-t px-3 py-2">
							<div className="flex flex-row items-center gap-0.5">
								<div className="flex min-w-0 shrink-0 cursor-pointer select-none flex-row">
									<TopicSelector />
								</div>
							</div>
							<div className="flex w-auto items-center justify-end">
								<div className="flex min-w-0 shrink-0 cursor-pointer select-none flex-row gap-x-2">
									<Button size="sm" type="button" variant="ghost" onClick={undoEditing}>
										Cancel
									</Button>
									<Button size="sm" disabled={isFetching}>
										Save
									</Button>
								</div>
							</div>
						</div>
					</form>
				</Form>
			</div>
		</div>
	)
})

LinkManage.displayName = "LinkManage"
LinkForm.displayName = "LinkForm"

export { LinkManage, LinkForm }
