import { useEffect, useState } from 'react';
import { Navigate, Outlet, useNavigate } from 'react-router-dom';
import { PresenceProvider } from '../../contexts/PresenceContext';
import { KeybindProvider } from '../../contexts/KeybindContext';
import { UserSettingsModal } from '../settings/UserSettingsModal';
import { ServerSettingsModal } from '../settings/ServerSettingsModal';
import { GuildsLayout } from './GuildsLayout';
import { CreateChannelModal } from './CreateChannelModal';
import { CreateCategoryModal } from './CategorySettingsModal';
import { InviteModal } from '../modals/InviteModal';
import { CreateServerModal } from '../modals/CreateServerModal';
import { PiPOverlay } from '../voice/PiPOverlay';
import { RecordingRecoveryModal } from '../voice/RecordingRecoveryModal';
import { ChannelSettingsModal } from '../channel/ChannelSettingsModal';
import { UpdateBanner } from './UpdateBanner';

/**
 * AppLayout — checks session via sessionStorage (matches App.tsx AuthGuard),
 * then renders the 3-column GuildsLayout with the active route's content
 * flowing through `<Outlet />`. Hosts the global user settings modal and
 * the server-level create/invite/settings modals, and listens for
 * `brycord:open-*` events to open them.
 */
export function AppLayout() {
	const navigate = useNavigate();
	const [settingsOpen, setSettingsOpen] = useState(false);
	// Optional tab request from the dispatcher — e.g. Edit Profile
	// buttons pass `{ tab: 'account' }` to jump straight in, while the
	// gear button passes nothing so mobile lands on the category list.
	const [settingsInitialTab, setSettingsInitialTab] = useState<
		'account' | 'appearance' | 'voice' | 'keybinds' | 'notifications' | 'security' | undefined
	>(undefined);
	const [createChannelOpen, setCreateChannelOpen] = useState(false);
	const [createCategoryOpen, setCreateCategoryOpen] = useState(false);
	const [inviteOpen, setInviteOpen] = useState(false);
	const [serverSettingsOpen, setServerSettingsOpen] = useState(false);
	const [createServerOpen, setCreateServerOpen] = useState(false);
	const [channelSettingsId, setChannelSettingsId] = useState<string | null>(null);

	// Keybind / cross-component nav bridge
	useEffect(() => {
		const onNavigate = (e: Event) => {
			const detail = (e as CustomEvent<{ path?: string }>).detail;
			if (detail?.path) navigate(detail.path);
		};
		window.addEventListener('brycord:navigate', onNavigate);
		return () => window.removeEventListener('brycord:navigate', onNavigate);
	}, [navigate]);

	// User settings trigger — fired by UserArea's gear button + other entry points
	useEffect(() => {
		const onOpenSettings = (e: Event) => {
			const detail = (e as CustomEvent<{ tab?: string }>).detail;
			const tab = detail?.tab as typeof settingsInitialTab;
			setSettingsInitialTab(tab);
			setSettingsOpen(true);
		};
		window.addEventListener('brycord:open-user-settings', onOpenSettings);
		return () => window.removeEventListener('brycord:open-user-settings', onOpenSettings);
	}, []);

	// Server-level modal triggers dispatched from GuildHeaderDropdown etc.
	useEffect(() => {
		const handlers: Record<string, () => void> = {
			'brycord:open-create-channel': () => setCreateChannelOpen(true),
			'brycord:open-create-category': () => setCreateCategoryOpen(true),
			'brycord:open-invite': () => setInviteOpen(true),
			'brycord:open-server-settings': () => setServerSettingsOpen(true),
			'brycord:open-create-server': () => setCreateServerOpen(true),
		};
		Object.entries(handlers).forEach(([k, h]) => window.addEventListener(k, h));
		return () => {
			Object.entries(handlers).forEach(([k, h]) => window.removeEventListener(k, h));
		};
	}, []);

	// Channel settings — fired by the sidebar gear icon with a channelId
	// payload. Single state holds the target id; null closes the modal.
	useEffect(() => {
		const onOpen = (e: Event) => {
			const detail = (e as CustomEvent<{ channelId?: string }>).detail;
			if (detail?.channelId) setChannelSettingsId(detail.channelId);
		};
		window.addEventListener('brycord:open-channel-settings', onOpen);
		return () =>
			window.removeEventListener('brycord:open-channel-settings', onOpen);
	}, []);

	// Global keybind handlers. Voice bindings are wired from UserArea
	// via its own `useVoice()` access so the dispatch arrives where the
	// mute / deafen state already lives.
	useEffect(() => {
		const goHome = () => navigate('/channels/@me');
		const focusSearch = () => {
			const input = document.querySelector<HTMLInputElement>(
				'input[placeholder="Search" i], input[aria-label="Search" i]',
			);
			input?.focus();
		};
		const openSettings = () => setSettingsOpen(true);
		window.addEventListener('brycord:keybind:navigation.goToDMs', goHome);
		window.addEventListener('brycord:keybind:navigation.focusSearch', focusSearch);
		window.addEventListener('brycord:keybind:popouts.openUserSettings', openSettings);
		return () => {
			window.removeEventListener('brycord:keybind:navigation.goToDMs', goHome);
			window.removeEventListener(
				'brycord:keybind:navigation.focusSearch',
				focusSearch,
			);
			window.removeEventListener(
				'brycord:keybind:popouts.openUserSettings',
				openSettings,
			);
		};
	}, [navigate]);

	const hasSession =
		typeof sessionStorage !== 'undefined' &&
		!!(sessionStorage.getItem('privateKey') && sessionStorage.getItem('signingKey'));

	const myUserId =
		typeof localStorage !== 'undefined' ? localStorage.getItem('userId') : null;

	if (!hasSession) {
		return <Navigate to="/login" replace />;
	}

	return (
		<PresenceProvider userId={myUserId}>
		<KeybindProvider>
			<GuildsLayout>
				<Outlet />
			</GuildsLayout>
			<UserSettingsModal
				isOpen={settingsOpen}
				onClose={() => {
					setSettingsOpen(false);
					setSettingsInitialTab(undefined);
				}}
				initialTab={settingsInitialTab}
			/>
			<ServerSettingsModal
				isOpen={serverSettingsOpen}
				onClose={() => setServerSettingsOpen(false)}
			/>
			<CreateChannelModal
				isOpen={createChannelOpen}
				onClose={() => setCreateChannelOpen(false)}
			/>
			<CreateCategoryModal
				isOpen={createCategoryOpen}
				onClose={() => setCreateCategoryOpen(false)}
			/>
			<InviteModal isOpen={inviteOpen} onClose={() => setInviteOpen(false)} />
			<CreateServerModal
				isOpen={createServerOpen}
				onClose={() => setCreateServerOpen(false)}
			/>
			<ChannelSettingsModal
				isOpen={!!channelSettingsId}
				onClose={() => setChannelSettingsId(null)}
				channelId={channelSettingsId}
			/>
			<PiPOverlay />
			<RecordingRecoveryModal />
			<UpdateBanner />
		</KeybindProvider>
		</PresenceProvider>
	);
}
