import {
	type Ref,
	createContext,
	memo,
	useContext,
	useEffect,
	useRef,
} from "react"
import { create } from "zustand"
import { useShallow } from "zustand/react/shallow"
import { Button } from "~/components/button"
import { DEFAULT_NODE, type Entry } from "~/home/graph"
import { useStore } from "./store"

function ApplicationList() {
	const entries = useStore(useShallow((state) => state.entries))
	return Object.values(entries).map((entry) => (
		<ApplicationListItem key={entry.name} entry={entry} />
	))
}

interface ListItemStore {
	isAddingStage: boolean
	newStageValue: string

	setNewStageValue: (newStageValue: string) => void
	setIsAddingStage: (isAddingStage: boolean) => void
	addStage: (entryName: string) => void
}

const useListItemStore = create<ListItemStore>()((set, get) => ({
	isAddingStage: false,
	newStageValue: "",

	setNewStageValue: (newStageValue: string) => set({ newStageValue }),
	setIsAddingStage: (isAddingStage: boolean) => set({ isAddingStage }),
	addStage: (entryName) => {
		const store = useStore.getState()
		let stage = get().newStageValue
		if (stage) {
			if (stage === DEFAULT_NODE.acceptedNode.key.toLowerCase()) {
				stage = DEFAULT_NODE.acceptedNode.key
			} else if (stage === DEFAULT_NODE.rejectedNode.key.toLowerCase()) {
				stage = DEFAULT_NODE.rejectedNode.key
			}
			store.addStageInEntry(stage, entryName)
			set({ isAddingStage: false, newStageValue: "" })
		}
	},
}))

const EntryContext = createContext<Entry>(null as unknown as Entry)

const ApplicationListItem = memo(({ entry }: { entry: Entry }) => (
	<EntryContext value={entry}>
		<details className="w-full px-2 pb-2 -mx-2">
			<summary className="cursor-pointer">{entry.name}</summary>
			<ol className="pl-3 list-decimal list-inside text-sm">
				{entry.stages.map((step) => (
					<StageItem key={step} step={step} />
				))}
				<NewStageInput />
			</ol>
			<ApplicationActions />
		</details>
	</EntryContext>
))

const StageItem = memo(({ step }: { step: string }) => {
	const entry = useContext(EntryContext)
	const deleteStageInEntry = useStore((state) => state.deleteStageInEntry)
	return (
		<li key={step} className="w-full group justify-between px-1">
			<div className="w-[90%] inline-flex flex-row items-center justify-between">
				{step}
				{step !== DEFAULT_NODE.applicationSubmittedNode.key ? (
					<Button
						variant="small"
						onClick={() => {
							deleteStageInEntry(step, entry.name)
						}}
						className="invisible group-hover:visible"
					>
						Delete
					</Button>
				) : null}
			</div>
		</li>
	)
})

function NewStageInput() {
	const isAddingStage = useListItemStore((state) => state.isAddingStage)
	const inputRef = useRef<HTMLInputElement | null>(null)

	useEffect(() => {
		if (isAddingStage) {
			inputRef.current?.focus()
		}
	}, [isAddingStage])

	if (isAddingStage) {
		return (
			<li className="px-1">
				<ActualStageInput ref={inputRef} />
			</li>
		)
	}
	return null
}
function ActualStageInput({ ref }: { ref: Ref<HTMLInputElement> }) {
	const entry = useContext(EntryContext)
	const newStageValue = useListItemStore((state) => state.newStageValue)
	const setNewStageValue = useListItemStore((state) => state.setNewStageValue)
	const addStage = useListItemStore((state) => state.addStage)

	return (
		<input
			ref={ref}
			value={newStageValue}
			onChange={(event) => {
				setNewStageValue(event.currentTarget.value)
			}}
			onKeyDown={(event) => {
				if (event.key === "Enter") {
					addStage(entry.name)
				}
			}}
			className="bg-transparent"
		/>
	)
}

function ApplicationActions() {
	const isAddingStage = useListItemStore((state) => state.isAddingStage)
	if (isAddingStage) {
		return <AddStageActions />
	}
	return <DefaultActions />
}

const DefaultActions = memo(() => {
	const entry = useContext(EntryContext)
	const setIsAddingStage = useListItemStore((state) => state.setIsAddingStage)
	const addStageToEntry = useStore((state) => state.addStageInEntry)
	const deleteEntry = useStore((state) => state.deleteEntry)

	const isApplicationFinalized =
		entry.stages.at(-1) === DEFAULT_NODE.acceptedNode.key ||
		entry.stages.at(-1) === DEFAULT_NODE.rejectedNode.key

	function onDeleteApplication() {
		if (confirm("Are you sure you want to delete this application?")) {
			deleteEntry(entry.name)
		}
	}

	function onAccepted() {
		addStageToEntry(DEFAULT_NODE.acceptedNode.key, entry.name)
	}

	function onRejected() {
		addStageToEntry(DEFAULT_NODE.rejectedNode.key, entry.name)
	}

	return (
		<div className="flex flex-row flex-wrap gap-2 pl-4 mt-2">
			<Button
				variant="small"
				disabled={isApplicationFinalized}
				onClick={() => {
					setIsAddingStage(true)
				}}
			>
				New stage
			</Button>
			<Button
				variant="small"
				disabled={isApplicationFinalized}
				onClick={onAccepted}
			>
				Accepted
			</Button>
			<Button
				variant="small"
				disabled={isApplicationFinalized}
				onClick={onRejected}
			>
				Rejected
			</Button>
			<Button variant="small" onClick={onDeleteApplication}>
				Delete application
			</Button>
		</div>
	)
})

const AddStageActions = memo(() => {
	const entry = useContext(EntryContext)
	const setIsAddingStage = useListItemStore((state) => state.setIsAddingStage)
	const addStage = useListItemStore((state) => state.addStage)

	function onOk() {
		addStage(entry.name)
	}

	function onCancel() {
		setIsAddingStage(false)
	}

	return (
		<div className="flex flex-row space-x-2 pl-4 mt-2">
			<Button variant="small" onClick={onOk}>
				Ok
			</Button>
			<Button variant="small" onClick={onCancel}>
				Cancel
			</Button>
		</div>
	)
})

export { ApplicationList }
