import "./index.scss";

import clsx from "clsx";
import { useEffect, useRef, useState } from "react";

export type SidebarProps = React.HTMLAttributes<HTMLDivElement> & {
	open?: boolean;
	onClose?: () => void;
	overlayProps?: React.HTMLAttributes<HTMLDivElement>;
	pullRight?: boolean;
	shadow?: boolean;
};

export function Sidebar(props: SidebarProps) {
	const {
		children,
		className,
		open = false,
		onClose = () => {},
		overlayProps = {},
		pullRight = false,
		shadow = true,
		...other
	} = props;

	const [hidden, setHidden] = useState(!open);
	const sidebar = useRef<HTMLDivElement>(null);
	const prevFocus = useRef<HTMLElement | null>(null);

	function closeSidebar() {
		if (open && typeof onClose === "function") {
			onClose();
		}
	}

	useEffect(() => {
		let element = sidebar.current;

		if (open) {
			setHidden(false);
		}

		function toggleHiddenContent() {
			setHidden(!open);
		}

		element?.addEventListener("transitionend", toggleHiddenContent);

		return () => element?.removeEventListener("transitionend", toggleHiddenContent);
	}, [open]);

	// oxlint-disable-next-line react-hooks/exhaustive-deps -- TODO
	useEffect(() => {
		function handleCloseSidebar(evt: KeyboardEvent) {
			if (evt.key === "Escape") {
				evt.stopPropagation();
				closeSidebar();
			}
		}

		window.addEventListener("keyup", handleCloseSidebar);

		return () => window.removeEventListener("keyup", handleCloseSidebar);
	}, [open, onClose]);

	useEffect(() => {
		if (open) {
			prevFocus.current = document.activeElement as HTMLElement | null;

			const firstFocusable = sidebar.current?.querySelector(
				'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])',
			) as HTMLElement | undefined;

			if (firstFocusable) {
				firstFocusable.focus();
			}
		} else if (prevFocus.current) {
			prevFocus.current.focus();
			prevFocus.current = null;
		}

		let prevFocusElem = prevFocus.current;

		return () => {
			if (open && prevFocusElem) {
				prevFocusElem.focus();
			}
		};
	}, [open]);

	const { className: overlayClassName, ...overlayOther } = overlayProps;

	return (
		<>
			<div
				className={clsx(
					"ObSidebar-root",
					open && "Ob-open",
					pullRight && "Ob-right",
					shadow && "ObSidebar-shadow",
					className,
				)}
				ref={sidebar}
				tabIndex={-1}
				{...other}
			>
				{(open || !hidden) && children}
			</div>
			{/** oxlint-disable-next-line jsx-a11y/no-static-element-interactions -- legacy component */}
			<div
				role="presentation"
				tabIndex={-1}
				className={clsx("ObSidebar-overlay", open && "Ob-open", overlayClassName)}
				onClick={closeSidebar}
				{...overlayOther}
			/>
		</>
	);
}
