/**
 * JTZL_WebIRC_Chat - Sidebar Provider Component
 *
 * @package   JTZL_WebIRC_Chat
 * @copyright Copyright (c) 2025, JT. G.
 * @license   GPL-3.0+
 * @since     3.0.0
 */

import * as React from 'react';
import { cn } from '../../lib/utils';

interface SidebarContext {
	state: 'expanded' | 'collapsed';
	open: boolean;
	setOpen: (open: boolean) => void;
	openMobile: boolean;
	setOpenMobile: (open: boolean) => void;
	isMobile: boolean;
	toggleSidebar: () => void;
}

const SidebarContext = React.createContext<SidebarContext | null>(null);

/**
 * Hook to access sidebar context.
 *
 * @since 3.0.0
 *
 * @return SidebarContext - Sidebar context object
 */
export function useSidebar(): SidebarContext {
	const context = React.useContext(SidebarContext);
	if (!context) {
		throw new Error('useSidebar must be used within a SidebarProvider.');
	}
	return context;
}

export interface SidebarProviderProps {
	defaultOpen?: boolean;
	open?: boolean;
	onOpenChange?: (open: boolean) => void;
	className?: string;
	style?: React.CSSProperties;
	children: React.ReactNode;
}

/**
 * Sidebar provider component for managing sidebar state and responsive behavior.
 *
 * @since 3.0.0
 *
 * @param props              - SidebarProvider component props
 * @param props.defaultOpen  - Default open state for the sidebar
 * @param props.open         - Controlled open state for the sidebar
 * @param props.onOpenChange - Callback when open state changes
 * @param props.className    - Additional CSS classes
 * @param props.style        - Inline styles
 * @param props.children     - Child components
 * @return JSX.Element - Rendered sidebar provider component
 */
export function SidebarProvider({
	defaultOpen = true,
	open: openProp,
	onOpenChange: setOpenProp,
	className,
	style,
	children,
	...props
}: SidebarProviderProps) {
	const [_open, _setOpen] = React.useState(defaultOpen);
	const [openMobile, setOpenMobile] = React.useState(false);
	const [isMobile, setIsMobile] = React.useState(false);

	// Use controlled or uncontrolled state.
	const open = openProp ?? _open;
	const setOpen = React.useCallback(
		(value: boolean | ((prevOpen: boolean) => boolean)) => {
			const openState = typeof value === 'function' ? value(open) : value;
			if (setOpenProp) {
				setOpenProp(openState);
			} else {
				_setOpen(openState);
			}

			// Store preference in localStorage for better security and persistence.
			try {
				localStorage.setItem(
					'sidebar:state',
					openState ? 'true' : 'false'
				);
			} catch {
				// Fallback to cookie if localStorage is not available.
				const secure =
					window.location.protocol === 'https:' ? '; Secure' : '';
				document.cookie = `sidebar:state=${openState ? 'true' : 'false'}; path=/; max-age=${60 * 60 * 24 * 7}; SameSite=Lax${secure}`;
			}
		},
		[setOpenProp, open]
	);

	// Toggle sidebar function.
	const toggleSidebar = React.useCallback(() => {
		return isMobile
			? setOpenMobile((prevOpen) => !prevOpen)
			: setOpen((prevOpen) => !prevOpen);
	}, [isMobile, setOpen, setOpenMobile]);

	// Detect mobile viewport.
	React.useEffect(() => {
		const handleResize = () => {
			setIsMobile(window.innerWidth < 768);
		};

		handleResize();
		window.addEventListener('resize', handleResize);
		return () => window.removeEventListener('resize', handleResize);
	}, []);

	// Close mobile sidebar when clicking outside.
	React.useEffect(() => {
		if (!isMobile || !openMobile) return;

		const handleClickOutside = (event: MouseEvent) => {
			const sidebar = document.querySelector('[data-sidebar="sidebar"]');
			if (sidebar && !sidebar.contains(event.target as Node)) {
				setOpenMobile(false);
			}
		};

		document.addEventListener('mousedown', handleClickOutside);
		return () =>
			document.removeEventListener('mousedown', handleClickOutside);
	}, [isMobile, openMobile]);

	// Load saved state from localStorage on mount.
	React.useEffect(() => {
		try {
			const value = localStorage.getItem('sidebar:state');
			if (value !== null) {
				setOpen(value === 'true');
			}
		} catch {
			// Fallback to cookie if localStorage is not available.
			const value = document.cookie.match(/sidebar:state=([^;]+)/);
			if (value) {
				setOpen(value[1] === 'true');
			}
		}
		// eslint-disable-next-line react-hooks/exhaustive-deps
	}, []);

	// Use the appropriate open state based on mobile/desktop
	const effectiveOpen = isMobile ? openMobile : open;
	const effectiveState = (effectiveOpen ? 'expanded' : 'collapsed') as
		| 'expanded'
		| 'collapsed';

	const contextValue = React.useMemo(
		() => ({
			state: effectiveState,
			open: effectiveOpen,
			setOpen,
			isMobile,
			openMobile,
			setOpenMobile,
			toggleSidebar,
		}),
		[
			effectiveState,
			effectiveOpen,
			setOpen,
			isMobile,
			openMobile,
			setOpenMobile,
			toggleSidebar,
		]
	);

	return (
		<SidebarContext.Provider value={contextValue}>
			<div
				style={
					{
						'--sidebar-width': '16rem',
						'--sidebar-width-icon': '3rem',
						...style,
					} as React.CSSProperties
				}
				className={cn(
					'group/sidebar-wrapper flex min-h-svh w-full has-[[data-variant=inset]]:bg-sidebar',
					className
				)}
				{...props}
			>
				{children}
			</div>
		</SidebarContext.Provider>
	);
}
