import { useEffect, useMemo, useRef, useState } from '@wordpress/element';
import { applyFilters, doAction } from '@wordpress/hooks';
import Welcome from './pages/Welcome';
import Layout from './components/Layout';
import Library from './pages/Library';
import MyBlocks from './pages/MyBlocks';
import MyLibrary from './pages/MyLibrary';
import ThemeConfig from './pages/ThemeConfig';
import BlockEditor from './pages/BlockEditor';
import ContentEditor from './pages/ContentEditor';
import { confirmLeave } from './unsavedChanges';
import { HOOKS } from './extensibility';

const DEFAULT_SHELL_ROUTES = [
	'library',
	'my-blocks',
	'theme',
	'gutenberg-blocks',
	'shortcode-blocks',
];

function readOwnerLibraryState() {
	return (
		( typeof jocbmAdmin !== 'undefined' &&
			jocbmAdmin.ownerLibrary ) ||
		{}
	);
}

const initialRoute = () => {
	const welcomeSeen = Boolean(
		typeof jocbmAdmin !== 'undefined' && jocbmAdmin.welcomeSeen
	);
	const hash = window.location.hash.replace( /^#\/?/, '' );
	const owner = readOwnerLibraryState();

	if ( welcomeSeen && ( ! hash || hash === 'welcome' ) ) {
		if ( owner.wantsGate && ! owner.unlocked ) {
			return 'owner-unlock';
		}
		if ( owner.wantsGate && owner.unlocked ) {
			return 'owner-blocks';
		}
		const fallback = applyFilters( HOOKS.DEFAULT_ROUTE, 'my-blocks' );
		return typeof fallback === 'string' && fallback ? fallback : 'my-blocks';
	}

	if ( hash && hash !== 'welcome' ) {
		return hash;
	}

	if ( ! welcomeSeen ) {
		return 'welcome';
	}

	if ( owner.wantsGate && ! owner.unlocked ) {
		return 'owner-unlock';
	}
	if ( owner.wantsGate && owner.unlocked ) {
		return 'owner-blocks';
	}

	const fallback = applyFilters( HOOKS.DEFAULT_ROUTE, 'my-blocks' );
	return typeof fallback === 'string' && fallback ? fallback : 'my-blocks';
};

export default function App() {
	const [ route, setRoute ] = useState( initialRoute );
	const [ editorContext, setEditorContext ] = useState( null );
	const routeRef = useRef( route );

	const shellRoutes = useMemo(
		() => applyFilters( HOOKS.SHELL_ROUTES, [ ...DEFAULT_SHELL_ROUTES ] ),
		[]
	);

	useEffect( () => {
		routeRef.current = route;
	}, [ route ] );

	useEffect( () => {
		const onHash = () => {
			const next =
				window.location.hash.replace( /^#\/?/, '' ) ||
				applyFilters( HOOKS.FALLBACK_SHELL_ROUTE, 'my-blocks', '' );
			if ( next === routeRef.current ) {
				return;
			}
			if ( ! confirmLeave() ) {
				const current = routeRef.current || 'my-blocks';
				const desired =
					current === 'my-blocks' ? '#/my-blocks' : `#/${ current }`;
				if (
					window.location.hash !== desired &&
					window.location.hash !== `#${ current }`
				) {
					window.location.hash = current;
				}
				return;
			}
			setRoute( next );
		};
		window.addEventListener( 'hashchange', onHash );
		return () => window.removeEventListener( 'hashchange', onHash );
	}, [] );

	const navigate = ( path, ctx = null ) => {
		if ( path === routeRef.current ) {
			// Always replace context so a prior My Library block cannot leak
			// into Owner Library (and vice versa) when re-entering the same route.
			setEditorContext( ctx );
			return;
		}
		if ( ! confirmLeave() ) {
			return;
		}
		setEditorContext( ctx );
		window.location.hash = path;
		setRoute( path );
	};

	useEffect( () => {
		doAction( HOOKS.ADMIN_READY, { navigate, route } );
	}, [] ); // eslint-disable-line react-hooks/exhaustive-deps -- fire once on mount

	useEffect( () => {
		if (
			route === 'welcome' &&
			typeof jocbmAdmin !== 'undefined' &&
			jocbmAdmin.welcomeSeen
		) {
			navigate( 'my-blocks' );
		}
	}, [ route ] ); // eslint-disable-line react-hooks/exhaustive-deps

	if ( route === 'welcome' ) {
		if ( typeof jocbmAdmin !== 'undefined' && jocbmAdmin.welcomeSeen ) {
			return null;
		}
		return <Welcome onStart={ () => navigate( 'my-blocks' ) } />;
	}

	const fullscreenPage = applyFilters(
		HOOKS.RENDER_FULLSCREEN_PAGE,
		null,
		route,
		{ navigate, editorContext, setEditorContext }
	);
	if ( fullscreenPage ) {
		return fullscreenPage;
	}

	if ( route.startsWith( 'editor/' ) || route === 'editor' ) {
		return (
			<BlockEditor
				key={ route }
				context={ editorContext }
				route={ route }
				onBack={ () => navigate( 'gutenberg-blocks' ) }
			/>
		);
	}

	if ( route.startsWith( 'content/' ) ) {
		return (
			<ContentEditor
				key={ route }
				route={ route }
				onBack={ () => navigate( 'shortcode-blocks' ) }
			/>
		);
	}

	const fallbackRoute = applyFilters(
		HOOKS.FALLBACK_SHELL_ROUTE,
		'my-blocks',
		route
	);
	const shellRoute = shellRoutes.includes( route )
		? route
		: fallbackRoute;

	const extensionPage = applyFilters(
		HOOKS.RENDER_SHELL_PAGE,
		null,
		route,
		{ navigate, editorContext }
	);

	return (
		<Layout route={ shellRoute } onNavigate={ navigate }>
			{ extensionPage }
			{ ! extensionPage && route === 'library' && (
				<Library onNavigate={ navigate } />
			) }
			{ ! extensionPage && route === 'my-blocks' && (
				<MyBlocks onNavigate={ navigate } />
			) }
			{ ! extensionPage &&
				( route === 'gutenberg-blocks' ||
					route === 'shortcode-blocks' ) && (
					<MyLibrary
						onNavigate={ navigate }
						section={
							route === 'shortcode-blocks'
								? 'shortcodes'
								: 'blocks'
						}
					/>
				) }
			{ ! extensionPage && route === 'theme' && (
				<ThemeConfig onNavigate={ navigate } />
			) }
			{ ! extensionPage && ! shellRoutes.includes( route ) && (
				<MyBlocks onNavigate={ navigate } />
			) }
		</Layout>
	);
}
