import { useEffect, useMemo, useState } from '@wordpress/element';
import { applyFilters } from '@wordpress/hooks';
import { __ } from '@wordpress/i18n';
import { api } from '../api';
import { LibraryFilterContext } from './LibraryFilterContext';
import { HOOKS } from '../extensibility';
import { brandLogoUrl } from '../../shared/brandLogo';

const DEFAULT_NAV = [
	{
		id: 'my-blocks',
		label: __( 'Dashboard', 'joc-blockora-morph' ),
		icon: 'dashboard',
	},
	{
		id: 'gutenberg-blocks',
		label: __( 'My Library', 'joc-blockora-morph' ),
		icon: 'category',
	},
	{
		id: 'library',
		label: __( 'JBM Library', 'joc-blockora-morph' ),
		icon: 'portfolio',
	},
	{
		id: 'theme',
		label: __( 'Global Settings', 'joc-blockora-morph' ),
		icon: 'admin-generic',
	},
];

const MY_LIBRARY_ROUTES = [ 'gutenberg-blocks', 'shortcode-blocks' ];
const MD_QUERY = '(min-width: 768px)';

function CatButton( { active, onClick, label, count, nested, pro } ) {
	return (
		<button
			type="button"
			className={
				active
					? `bm-cat-link is-active${ nested ? ' is-nested' : '' }`
					: `bm-cat-link${ nested ? ' is-nested' : '' }`
			}
			onClick={ onClick }
		>
			<span className="bm-cat-label">
				{ label }
				{ pro ? (
					<em className="bm-cat-pro">{ __( 'Pro', 'joc-blockora-morph' ) }</em>
				) : null }
			</span>
			<em className="bm-cat-count">{ count }</em>
		</button>
	);
}

export default function Layout( { route, onNavigate, children } ) {
	const version = jocbmAdmin?.version || '0.1.0';
	const cmsUrl = jocbmAdmin?.cmsUrl || '/wp-admin/';
	const isLibrary = route === 'library';
	const isMyLibrary = MY_LIBRARY_ROUTES.includes( route );

	// Re-filter each render so Pro can show Owner Library after unlock.
	const nav = applyFilters( HOOKS.ADMIN_NAV, [ ...DEFAULT_NAV ] );

	const isNavActive = ( itemId ) => {
		if ( itemId === 'gutenberg-blocks' ) {
			return isMyLibrary;
		}
		if ( itemId === 'owner-library' || itemId === 'owner-blocks' ) {
			return (
				route === 'owner-library' ||
				route === 'owner-blocks' ||
				route === 'owner-unlock'
			);
		}
		return route === itemId;
	};

	const [ categories, setCategories ] = useState( [] );
	const [ categoryTree, setCategoryTree ] = useState( [] );
	const [ featuredCount, setFeaturedCount ] = useState( 0 );
	const [ blockCount, setBlockCount ] = useState( 0 );
	const [ activeCat, setActiveCat ] = useState( 'all' );
	const [ openGroups, setOpenGroups ] = useState( {} );
	const [ menuOpen, setMenuOpen ] = useState( false );

	const closeMenu = () => setMenuOpen( false );

	const goTo = ( id ) => {
		onNavigate( id );
		closeMenu();
	};

	const pickCategory = ( slug ) => {
		setActiveCat( slug );
		closeMenu();
	};

	useEffect( () => {
		if ( ! isLibrary ) {
			return;
		}
		Promise.all( [ api.get( '/categories' ), api.get( '/system-blocks' ) ] )
			.then( ( [ cats, blks ] ) => {
				const tree = cats.tree || [];
				setCategories( cats.items || [] );
				setCategoryTree( tree );
				setFeaturedCount( cats.featuredCount || 0 );
				setBlockCount( ( blks.items || [] ).length );

				const nextOpen = {};
				tree.forEach( ( group ) => {
					const hasBlocks = ( group.blockCount || 0 ) > 0;
					nextOpen[ group.slug ] = hasBlocks;
				} );
				setOpenGroups( nextOpen );
			} )
			.catch( () => {
				setCategories( [] );
				setCategoryTree( [] );
				setFeaturedCount( 0 );
				setBlockCount( 0 );
			} );
	}, [ isLibrary ] );

	useEffect( () => {
		if ( ! isLibrary ) {
			setActiveCat( 'all' );
		}
	}, [ isLibrary ] );

	useEffect( () => {
		closeMenu();
	}, [ route ] );

	useEffect( () => {
		if ( typeof window === 'undefined' || ! window.matchMedia ) {
			return undefined;
		}
		const mq = window.matchMedia( MD_QUERY );
		const onChange = () => {
			if ( mq.matches ) {
				closeMenu();
			}
		};
		onChange();
		if ( mq.addEventListener ) {
			mq.addEventListener( 'change', onChange );
			return () => mq.removeEventListener( 'change', onChange );
		}
		mq.addListener( onChange );
		return () => mq.removeListener( onChange );
	}, [] );

	useEffect( () => {
		if ( ! menuOpen ) {
			return undefined;
		}
		const onKey = ( event ) => {
			if ( event.key === 'Escape' ) {
				closeMenu();
			}
		};
		document.addEventListener( 'keydown', onKey );
		const prevOverflow = document.body.style.overflow;
		document.body.style.overflow = 'hidden';
		return () => {
			document.removeEventListener( 'keydown', onKey );
			document.body.style.overflow = prevOverflow;
		};
	}, [ menuOpen ] );

	const filterValue = useMemo(
		() => ( {
			activeCat,
			setActiveCat,
			categories,
			categoryTree,
			featuredCount,
			blockCount,
		} ),
		[ activeCat, categories, categoryTree, featuredCount, blockCount ]
	);

	const visibleCategoryTree = useMemo(
		() =>
			( categoryTree || [] )
				.map( ( group ) => ( {
					...group,
					children: ( group.children || [] ).filter(
						( child ) => ( child.blockCount || 0 ) > 0
					),
				} ) )
				.filter( ( group ) => ( group.blockCount || 0 ) > 0 ),
		[ categoryTree ]
	);

	useEffect( () => {
		if ( activeCat === 'all' ) {
			return;
		}
		if ( activeCat === 'featured' ) {
			if ( featuredCount <= 0 ) {
				setActiveCat( 'all' );
			}
			return;
		}
		const exists = visibleCategoryTree.some(
			( group ) =>
				group.slug === activeCat ||
				( group.children || [] ).some( ( child ) => child.slug === activeCat )
		);
		if ( ! exists ) {
			setActiveCat( 'all' );
		}
	}, [ activeCat, featuredCount, visibleCategoryTree ] );

	const toggleGroup = ( slug ) => {
		setOpenGroups( ( prev ) => ( {
			...prev,
			[ slug ]: ! prev[ slug ],
		} ) );
	};

	return (
		<LibraryFilterContext.Provider value={ filterValue }>
			<div
				className={
					menuOpen
						? 'bm-shell bm-shell--menu-open flex h-screen overflow-hidden bg-surface-bg font-sans text-on-background antialiased'
						: 'bm-shell flex h-screen overflow-hidden bg-surface-bg font-sans text-on-background antialiased'
				}
			>
				{ menuOpen ? (
					<button
						type="button"
						className="bm-shell-backdrop"
						aria-label={ __( 'Close menu', 'joc-blockora-morph' ) }
						onClick={ closeMenu }
					/>
				) : null }

				<aside
					id="bm-shell-aside"
					className={
						menuOpen
							? 'bm-shell__aside is-open z-40 flex h-full w-sidebar-width shrink-0 flex-col'
							: 'bm-shell__aside z-40 flex h-full w-sidebar-width shrink-0 flex-col'
					}
				>
					<div className="bm-shell-brand">
						<div className="bm-shell-brand__atmosphere" aria-hidden="true" />
						<div className="bm-shell-brand__row">
							<div className="bm-shell-brand__mark">
								<img
									className="bm-shell-brand__logo"
									src={ brandLogoUrl() }
									alt=""
									width={ 60 }
									height={ 60 }
									decoding="async"
								/>
							</div>
							<div className="bm-shell-brand__copy">
								<p className="bm-shell-brand__eyebrow">JOC</p>
								<h2 className="bm-shell-brand__name">
									Blockora{ ' ' }
									<span className="bm-shell-brand__accent">
										Morph
									</span>
								</h2>
								<span className="bm-shell-brand__badge">
									v{ version }
									<em>{ __( 'Stable', 'joc-blockora-morph' ) }</em>
								</span>
							</div>
							<button
								type="button"
								className="bm-shell-brand__close"
								onClick={ closeMenu }
								aria-label={ __( 'Close menu', 'joc-blockora-morph' ) }
							>
								<span
									className="dashicons dashicons-no-alt"
									aria-hidden="true"
								/>
							</button>
						</div>
					</div>

					<nav
						className="bm-shell-nav custom-scrollbar flex-1 overflow-y-auto"
						aria-label={ __( 'Primary', 'joc-blockora-morph' ) }
					>
						<p className="bm-shell-nav__label">
							{ __( 'Workspace', 'joc-blockora-morph' ) }
						</p>
						<div className="bm-shell-nav__list">
							{ nav.map( ( item ) => (
								<button
									key={ item.id }
									type="button"
									className={
										isNavActive( item.id )
											? 'bm-nav-link is-active'
											: 'bm-nav-link'
									}
									onClick={ () => goTo( item.id ) }
								>
									<span
										className="bm-nav-link__icon"
										aria-hidden="true"
									>
										<span
											className={ `dashicons dashicons-${ item.icon }` }
										/>
									</span>
									<span className="bm-nav-link__text">
										{ item.label }
									</span>
								</button>
							) ) }
						</div>

						{ isLibrary && (
							<div className="bm-shell-nav__cats">
								<p className="bm-shell-nav__label">
									{ __( 'Categories', 'joc-blockora-morph' ) }
								</p>
								<CatButton
									active={ activeCat === 'all' }
									onClick={ () => pickCategory( 'all' ) }
									label={ __( 'All blocks', 'joc-blockora-morph' ) }
									count={ blockCount }
								/>
								{ featuredCount > 0 ? (
									<CatButton
										active={ activeCat === 'featured' }
										onClick={ () => pickCategory( 'featured' ) }
										label={ `⭐ ${ __( 'Featured', 'joc-blockora-morph' ) }` }
										count={ featuredCount }
									/>
								) : null }

								{ visibleCategoryTree.map( ( group ) => {
									const isOpen = Boolean( openGroups[ group.slug ] );
									const children = group.children || [];
									const hasChildren = children.length > 0;
									return (
										<div key={ group.slug } className="bm-cat-group">
											<div className="bm-cat-group__row">
												{ hasChildren ? (
													<button
														type="button"
														className="bm-cat-toggle"
														aria-expanded={ isOpen }
														aria-label={
															isOpen
																? __( 'Collapse', 'joc-blockora-morph' )
																: __( 'Expand', 'joc-blockora-morph' )
														}
														onClick={ () =>
															toggleGroup( group.slug )
														}
													>
														<span
															className={ `dashicons dashicons-arrow-${
																isOpen ? 'down' : 'right'
															}-alt2` }
															aria-hidden="true"
														/>
													</button>
												) : (
													<span
														className="bm-cat-toggle bm-cat-toggle--spacer"
														aria-hidden="true"
													/>
												) }
												<CatButton
													active={ activeCat === group.slug }
													onClick={ () => pickCategory( group.slug ) }
													label={ group.name }
													count={ group.blockCount || 0 }
													pro={ group.isPro }
												/>
											</div>
											{ isOpen &&
												hasChildren &&
												children.map( ( child ) => (
													<CatButton
														key={ child.slug }
														active={ activeCat === child.slug }
														onClick={ () =>
															pickCategory( child.slug )
														}
														label={ child.name }
														count={ child.blockCount || 0 }
														nested
														pro={ child.isPro }
													/>
												) ) }
										</div>
									);
								} ) }
							</div>
						) }
					</nav>

					<div className="bm-shell-foot">
						<button
							type="button"
							className="bm-shell-foot__cta"
							onClick={ () => goTo( 'library' ) }
						>
							<span
								className="dashicons dashicons-plus-alt2"
								aria-hidden="true"
							/>
							{ __( 'Browse JBM Library', 'joc-blockora-morph' ) }
						</button>
						<a href={ cmsUrl } className="bm-nav-link bm-nav-link--quiet">
							<span className="bm-nav-link__icon" aria-hidden="true">
								<span className="dashicons dashicons-wordpress" />
							</span>
							<span className="bm-nav-link__text">
								{ __( 'WordPress Admin', 'joc-blockora-morph' ) }
							</span>
						</a>
					</div>
				</aside>

				<div className="flex min-h-0 min-w-0 flex-1 flex-col overflow-hidden">
					<header className="bm-shell-header bm-glass sticky top-0 z-[15] flex h-header-height shrink-0 items-center gap-3 px-gutter">
						<button
							type="button"
							className="bm-shell-header__menu"
							aria-expanded={ menuOpen }
							aria-controls="bm-shell-aside"
							onClick={ () => setMenuOpen( ( open ) => ! open ) }
						>
							<span
								className={
									menuOpen
										? 'dashicons dashicons-no-alt'
										: 'dashicons dashicons-menu'
								}
								aria-hidden="true"
							/>
							<span className="bm-shell-header__menu-label">
								{ menuOpen
									? __( 'Close', 'joc-blockora-morph' )
									: __( 'Menu', 'joc-blockora-morph' ) }
							</span>
						</button>

						<div className="bm-shell-header__brand">
							<img
								src={ brandLogoUrl() }
								alt=""
								width={ 32 }
								height={ 32 }
								decoding="async"
							/>
							<span>
								Blockora
								<em> Morph</em>
							</span>
						</div>

						<div className="bm-shell-header__actions ml-auto flex items-center">
							<a
								href={ cmsUrl }
								className="bm-shell-header__wp"
								aria-label={ __( 'WordPress Admin', 'joc-blockora-morph' ) }
								title={ __( 'WordPress Admin', 'joc-blockora-morph' ) }
							>
								<span
									className="dashicons dashicons-wordpress-alt"
									aria-hidden="true"
								/>
							</a>
						</div>
					</header>
					<main className="min-h-0 flex-1 overflow-auto">{ children }</main>
				</div>
			</div>
		</LibraryFilterContext.Provider>
	);
}
