import { create } from "zustand/react"
import { subscribeWithSelector } from "zustand/middleware"
import type { Collection } from "@markone/core"
import { createContext, memo, useCallback, useContext, useEffect, useRef } from "react"
import { clsx } from "clsx"
import { Button } from "~/components/button"
import { useMnemonics } from "~/hooks/use-mnemonics"
import { DialogKind, useCollectionPageStore } from "./-store"
import { useStore } from "zustand"

export enum CollectionListItemAction {
	Delete = "Delete",
	Edit = "Edit",
}

type ItemActionCallback = (collection: Collection, action: CollectionListItemAction) => void

interface CollectionListProps {
	collections: Collection[]
	className?: string
}

interface CreateStoreOptions {
	collections: Collection[]
}

interface CollectionListState {
	collections: Collection[]
	selectedIndex: number
	selectedCollectionId: string
	isItemExpanded: boolean

	setCollections: (collections: Collection[]) => void
	setSelectedIndex: (index: number) => void
	setSelectedCollectionId: (id: string) => void
	setIsItemExpanded: (expanded: boolean) => void
}

type CollectionListStore = ReturnType<typeof createCollectionListStore>

const CollectionListStoreContext = createContext<CollectionListStore | null>(null)

function createCollectionListStore({ collections }: CreateStoreOptions) {
	return create<CollectionListState>()(
		subscribeWithSelector((set) => ({
			collections,
			selectedIndex: 0,
			selectedCollectionId: collections.length > 0 ? collections[0].id : "",
			isItemExpanded: false,

			setCollections(collections: Collection[]) {
				set({ collections, selectedCollectionId: collections.length > 0 ? collections[0].id : "", selectedIndex: 0 })
			},

			setSelectedIndex(index: number) {
				set({ selectedIndex: index })
			},

			setSelectedCollectionId(id: string) {
				set({ selectedCollectionId: id })
			},

			setIsItemExpanded(expanded: boolean) {
				set({ isItemExpanded: expanded })
			},
		})),
	)
}

function useCollectionListStoreContext() {
	const store = useContext(CollectionListStoreContext)
	if (!store) throw new Error("CollectionListStoreContext not found")
	return store
}

function useCollectionListStore<T>(selector: (state: CollectionListState) => T): T {
	const store = useCollectionListStoreContext()
	return useStore(store, selector)
}

function CollectionList({ collections, className }: CollectionListProps) {
	const storeRef = useRef<CollectionListStore | null>(null)
	if (!storeRef.current) {
		storeRef.current = createCollectionListStore({ collections })
	}

	useEffect(() => {
		// biome-ignore lint/style/noNonNullAssertion: storeRef.current is already set above, so cant be null
		const store = storeRef.current!
		store.getState().setCollections(collections)
	}, [collections])

	return (
		<CollectionListStoreContext.Provider value={storeRef.current}>
			<_CollectionList className={className} />
		</CollectionListStoreContext.Provider>
	)
}

const _CollectionList = memo(({ className }: { className?: string }) => {
	const store = useCollectionListStoreContext()
	const handleCollectionListAction = useCollectionPageStore((state) => state.handleCollectionListAction)

	useMnemonics(
		{
			j: selectNextItem,
			ArrowDown: selectNextItem,

			k: selectPrevItem,
			ArrowUp: selectPrevItem,

			h: collapseItem,
			ArrowLeft: collapseItem,

			l: expandItem,
			ArrowRight: expandItem,

			d: deleteItem,
			e: editItem,
		},
		{
			ignore: useCallback(() => useCollectionPageStore.getState().dialog.kind !== DialogKind.None, []),
		},
	)

	function deleteItem() {
		const { collections, selectedIndex } = store.getState()
		handleCollectionListAction(collections[selectedIndex], CollectionListItemAction.Delete)
	}

	function editItem() {
		const { collections, selectedIndex } = store.getState()
		handleCollectionListAction(collections[selectedIndex], CollectionListItemAction.Edit)
	}

	function selectPrevItem() {
		const { collections, selectedIndex, setSelectedCollectionId } = store.getState()
		const prevIndex = selectedIndex - 1
		if (prevIndex >= 0) {
			setSelectedCollectionId(collections[prevIndex].id)
		}
	}

	function selectNextItem() {
		const { collections, selectedIndex, setSelectedCollectionId } = store.getState()
		const nextIndex = selectedIndex + 1
		if (nextIndex < collections.length) {
			setSelectedCollectionId(collections[nextIndex].id)
		}
	}

	function expandItem() {
		store.getState().setIsItemExpanded(true)
	}

	function collapseItem() {
		store.getState().setIsItemExpanded(false)
	}

	return (
		<ul className={clsx("flex flex-col -mt-2", className)}>
			<ListContainer />
		</ul>
	)
})

function ListContainer() {
	const collections = useCollectionListStore((state) => state.collections)
	const selectedItemId = useCollectionListStore((state) => state.selectedCollectionId)

	return collections.length === 0 ? (
		<p>You have not created any collections!</p>
	) : (
		collections.map((collection, index) => (
			<CollectionListItem
				key={collection.id}
				collection={collection}
				selected={collection.id === selectedItemId}
				index={index}
			/>
		))
	)
}

const CollectionListItem = memo(
	({ collection, selected, index }: { collection: Collection; selected: boolean; index: number }) => {
		const store = useCollectionListStoreContext()
		const isItemExpanded = useCollectionListStore((state) => state.isItemExpanded)
		const setSelectedCollectionId = useCollectionListStore((state) => state.setSelectedCollectionId)
		const setIsItemExpanded = useCollectionListStore((state) => state.setIsItemExpanded)
		const handleCollectionListAction = useCollectionPageStore((state) => state.handleCollectionListAction)

		useEffect(() => {
			if (selected) {
				store.getState().setSelectedIndex(index)
			}
		}, [selected, index, store])

		function onItemHover() {
			if (!store.getState().isItemExpanded) {
				setSelectedCollectionId(collection.id)
			}
		}

		function deleteItem() {
			handleCollectionListAction(collection, CollectionListItemAction.Delete)
		}

		function editItem() {
			handleCollectionListAction(collection, CollectionListItemAction.Edit)
		}

		return (
			<li
				className={clsx("group flex flex-row justify-start py-2", {
					"bg-teal-600 text-stone-100": isItemExpanded && selected,
					"text-teal-600": selected && !isItemExpanded,
				})}
				onMouseEnter={onItemHover}
			>
				<button
					type="button"
					disabled={!selected}
					className={clsx("select-none flex items-start font-bold hover:bg-teal-600 hover:text-stone-100", {
						invisible: !selected,
					})}
					onClick={() => {
						setIsItemExpanded(!isItemExpanded)
					}}
				>
					<span className="sr-only">Options for this collection</span>
					<span>&nbsp;</span>
					<span className={isItemExpanded ? "rotate-90" : ""}>&gt;</span>
					<span>&nbsp;</span>
				</button>
				<div className="flex flex-col w-full">
					<div className="block w-full text-start font-bold">{collection.name}</div>
					<p className="opacity-80 text-sm">{collection.description}</p>
					{isItemExpanded && selected ? (
						<div className="flex flex-col space-y-1 md:flex-row md:space-y-0 md:space-x-2 items-end justify-between pt-2">
							<div className="flex space-x-2">
								<Button variant="light" className="text-sm" onClick={editItem}>
									<span className="underline">E</span>DIT
								</Button>
								<Button variant="light" className="text-sm" onClick={deleteItem}>
									<span className="underline">D</span>ELETE
								</Button>
								<span className="-ml-2">&nbsp;</span>
							</div>
						</div>
					) : null}
				</div>
			</li>
		)
	},
)

export { CollectionList }
export type { CollectionListState }
