import { Layout } from 'antd';
import { useEffect, useMemo, useState } from 'react';
import { Outlet, useLocation, useNavigate, useSearchParams } from 'react-router-dom';
import { useGestureLayer, useGesturePageState, useSearchLayer } from '../../../layer';
import { useAppStore } from '../../../store';
import { ChatRuntimeBridgeV2 } from '../ChatRuntimeBridgeV2';
import { syncAppConfigFromServer, useAppConfig } from '../appConfig';
import { useTokenAccess } from '../tokenAccess';
import { useUnreadCounts } from '../chatV2/hooks/useUnreadCounts';
import { matchesShortcut, isTypingTarget, scrollToElement } from '../mainView/utils';
import { MainContent } from '../MainContent';
import { MainHeader } from '../MainHeader';
import { MainSidebar } from '../MainSidebar';
import { appendPreviewRuntimeSearch, isPreviewRuntime, readPreviewRuntimeDeviceModeFromUrl } from '../previewRuntime';
import { buildSearchOptions } from './buildSearchOptions';
import { MainLayoutContextProvider } from './MainLayoutContext';
import { useMainLayoutData } from './useMainLayoutData';
import '../MainLayout.css';
import {
  buildApiMenuItems,
  buildApisPath,
  buildChatMenuItems,
  buildChatPath,
  buildDocsMenuItems,
  buildDocsPath,
  buildPlanMenuItems,
  buildPlansPath,
  buildPlayMenuItems,
  buildPlayPath,
  buildSavedLayoutPath,
  DOCS_DEFAULT_FOLDER,
  PLAN_MENU_ANCHOR_IDS,
  renderSidebarIntro,
  resolveCurrentPageDescriptor,
  resolvePlanQuickFilterMenu,
  resolvePlayOpenKeys,
  resolveSavedLayoutIdFromMenuKey,
  resolveTopMenuPath,
  type ApiSectionKey,
  type ChatSectionKey,
  type PlanSectionKey,
  type PlaySidebarKey,
  type TopMenuKey,
} from '../routes';

const E_READER_IMMERSIVE_BODY_CLASS = 'play-app-e-reader-immersive';

function parseRoute(pathname: string): {
  topMenu: TopMenuKey;
  docsMenu: string;
  apiMenu: ApiSectionKey;
  planMenu: PlanSectionKey;
  chatMenu: ChatSectionKey;
  playMenu: PlaySidebarKey;
} {
  const segments = pathname.split('/').filter(Boolean);
  const [top, first, second] = segments;

  if (top === 'docs') {
    return {
      topMenu: 'docs',
      docsMenu: first || DOCS_DEFAULT_FOLDER,
      apiMenu: 'components',
      planMenu: 'all',
      chatMenu: 'live',
      playMenu: 'layout',
    };
  }

  if (top === 'apis' && (first === 'components' || first === 'widgets')) {
    return {
      topMenu: 'apis',
      docsMenu: DOCS_DEFAULT_FOLDER,
      apiMenu: first,
      planMenu: 'all',
      chatMenu: 'live',
      playMenu: 'layout',
    };
  }

  if (
    top === 'plans' &&
    (first === 'all' ||
      first === 'in-progress' ||
      first === 'done' ||
      first === 'error' ||
      first === 'release' ||
      first === 'release-review' ||
      first === 'board' ||
      first === 'charts' ||
      first === 'schedule' ||
      first === 'history' ||
      first === 'automation-type' ||
      first === 'automation-context' ||
      first === 'token-setting' ||
      first === 'shared-resource' ||
      first === 'server-command')
  ) {
    return {
      topMenu: 'plans',
      docsMenu: DOCS_DEFAULT_FOLDER,
      apiMenu: 'components',
      planMenu: first,
      chatMenu: 'live',
      playMenu: 'layout',
    };
  }

  if (
    top === 'chat' &&
    (first === 'live' ||
      first === 'system' ||
      first === 'changes' ||
      first === 'resources' ||
      first === 'errors' ||
      first === 'manage' ||
      first === 'manage-defaults' ||
      first === 'manage-share')
  ) {
    return {
      topMenu: 'chat',
      docsMenu: DOCS_DEFAULT_FOLDER,
      apiMenu: 'components',
      planMenu: 'all',
      chatMenu: first,
      playMenu: 'layout',
    };
  }

  if (top === 'play' && (first === 'layout' || first === 'draw' || first === 'apps' || first === 'test' || first === 'cbt')) {
    return {
      topMenu: 'play',
      docsMenu: DOCS_DEFAULT_FOLDER,
      apiMenu: 'components',
      planMenu: 'all',
      chatMenu: 'live',
      playMenu: first,
    };
  }

  if (top === 'play' && first === 'layout-record' && second) {
    return {
      topMenu: 'play',
      docsMenu: DOCS_DEFAULT_FOLDER,
      apiMenu: 'components',
      planMenu: 'all',
      chatMenu: 'live',
      playMenu: `layout-record:${second}`,
    };
  }

  return {
    topMenu: 'chat',
    docsMenu: DOCS_DEFAULT_FOLDER,
    apiMenu: 'components',
    planMenu: 'all',
    chatMenu: 'live',
    playMenu: 'layout',
  };
}

function isRestrictedTopMenu(topMenu: TopMenuKey, hasAccess: boolean) {
  return !hasAccess && topMenu !== 'docs';
}

function getIsMobileViewport() {
  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
    return false;
  }

  if (readPreviewRuntimeDeviceModeFromUrl() === 'mobile') {
    return true;
  }

  return window.matchMedia('(max-width: 768px)').matches;
}

function getIsSidebarOverlayViewport(topMenu: TopMenuKey) {
  if (typeof window === 'undefined' || typeof window.matchMedia !== 'function') {
    return false;
  }

  if (readPreviewRuntimeDeviceModeFromUrl() === 'mobile') {
    return true;
  }

  return window.matchMedia(topMenu === 'chat' ? '(max-width: 1180px)' : '(max-width: 768px)').matches;
}

function resolveSidebarCollapsedForViewport(isSidebarOverlayViewport: boolean) {
  if (!isSidebarOverlayViewport) {
    return false;
  }

  return true;
}

function resolveSidebarOpenKeys(
  topMenu: TopMenuKey,
  hasAccess: boolean,
  planMenu: PlanSectionKey,
  chatMenu: ChatSectionKey,
) {
  if (!hasAccess) {
    return ['docs-group'];
  }

  if (topMenu === 'docs') {
    return ['docs-group'];
  }

  if (topMenu === 'apis') {
    return ['api-group'];
  }

  if (topMenu === 'play') {
    return resolvePlayOpenKeys();
  }

  if (topMenu === 'plans') {
    if (planMenu === 'server-command') {
      return ['server-group'];
    }

    if (planMenu === 'token-setting' || planMenu === 'shared-resource') {
      return ['token-management-group'];
    }

    return ['plan-group'];
  }

  if (chatMenu === 'errors') {
    return ['app-log-group'];
  }

  return chatMenu === 'manage' || chatMenu === 'manage-defaults' ? ['chat-manage-group'] : ['chat-group'];
}

export function MainLayout() {
  const previewRuntime = isPreviewRuntime();
  const location = useLocation();
  const navigate = useNavigate();
  const [searchParams] = useSearchParams();
  const { currentPage, focusedComponentId, setCurrentPage, setFocusedComponentId } = useAppStore();
  const { hasAccess } = useTokenAccess();
  const appConfig = useAppConfig();
  const { openSearch, setOptions: setSearchOptions } = useSearchLayer();
  const layoutData = useMainLayoutData();
  const routeState = useMemo(() => parseRoute(location.pathname), [location.pathname]);
  const [isMobileViewport, setIsMobileViewport] = useState(() => getIsMobileViewport());
  const [isEReaderImmersiveActive, setIsEReaderImmersiveActive] = useState(() =>
    typeof document !== 'undefined' ? document.body.classList.contains(E_READER_IMMERSIVE_BODY_CLASS) : false,
  );
  const [sidebarCollapsed, setSidebarCollapsed] = useState(() =>
    resolveSidebarCollapsedForViewport(getIsSidebarOverlayViewport(routeState.topMenu)),
  );
  const [isSidebarOverlayViewport, setIsSidebarOverlayViewport] = useState(() =>
    getIsSidebarOverlayViewport(routeState.topMenu),
  );
  const [contentExpanded, setContentExpanded] = useState(false);
  const [sidebarOpenKeys, setSidebarOpenKeys] = useState<string[]>(
    resolveSidebarOpenKeys(routeState.topMenu, hasAccess, routeState.planMenu, routeState.chatMenu),
  );
  const [activePlanQuickFilter, setActivePlanQuickFilter] = useState<
    'working' | 'release-pending-main' | 'automation-failed' | null
  >(routeState.planMenu === 'release' ? 'release-pending-main' : null);
  const [planQuickFilterRequestKey, setPlanQuickFilterRequestKey] = useState(routeState.planMenu === 'release' ? 1 : 0);
  const { componentSampleEntries, widgetSampleEntries, componentSamples, widgetSamples, docsDocuments, savedLayouts, savedLayoutsReady, setSavedLayouts, docFolders } = layoutData;
  const { chatUnreadCount } = useUnreadCounts();
  const navigateWithinApp = (path: string, options?: { replace?: boolean; resetSearch?: boolean }) => {
    const baseSearch = options?.resetSearch ? '' : location.search;
    const nextPath = previewRuntime ? appendPreviewRuntimeSearch(path, baseSearch) : path;
    navigate(nextPath, options?.replace == null ? undefined : { replace: options.replace });
  };


  useEffect(() => {
    void syncAppConfigFromServer();
  }, []);
  useEffect(() => {
    if (typeof document === 'undefined') {
      return undefined;
    }

    const body = document.body;
    const syncEReaderImmersiveState = () => {
      setIsEReaderImmersiveActive(body.classList.contains(E_READER_IMMERSIVE_BODY_CLASS));
    };

    syncEReaderImmersiveState();
    const observer = new MutationObserver(syncEReaderImmersiveState);
    observer.observe(body, { attributes: true, attributeFilter: ['class'] });

    return () => {
      observer.disconnect();
    };
  }, []);

  useEffect(() => {
    const mediaQuery = window.matchMedia('(max-width: 768px)');
    const updateViewport = () => {
      setIsMobileViewport(getIsMobileViewport());
    };

    updateViewport();
    mediaQuery.addEventListener('change', updateViewport);

    return () => {
      mediaQuery.removeEventListener('change', updateViewport);
    };
  }, []);

  useEffect(() => {
    const mediaQuery = window.matchMedia(routeState.topMenu === 'chat' ? '(max-width: 1180px)' : '(max-width: 768px)');
    const updateViewport = () => {
      setIsSidebarOverlayViewport(getIsSidebarOverlayViewport(routeState.topMenu));
    };

    updateViewport();
    mediaQuery.addEventListener('change', updateViewport);

    return () => {
      mediaQuery.removeEventListener('change', updateViewport);
    };
  }, [routeState.topMenu]);

  useEffect(() => {
    setSidebarCollapsed(resolveSidebarCollapsedForViewport(isSidebarOverlayViewport));
  }, [isSidebarOverlayViewport, routeState.topMenu]);

  useEffect(() => {
    setSidebarOpenKeys(resolveSidebarOpenKeys(routeState.topMenu, hasAccess, routeState.planMenu, routeState.chatMenu));
  }, [hasAccess, routeState.chatMenu, routeState.planMenu, routeState.topMenu]);

  useEffect(() => {
    if (docFolders.length > 0 && routeState.topMenu === 'docs' && !docFolders.includes(routeState.docsMenu)) {
      navigateWithinApp(buildDocsPath(docFolders[0]), { replace: true });
    }
  }, [docFolders, navigate, location.search, previewRuntime, routeState.docsMenu, routeState.topMenu]);

  useEffect(() => {
    const savedLayoutId = resolveSavedLayoutIdFromMenuKey(routeState.playMenu);

    if (savedLayoutId && savedLayoutsReady && !savedLayouts.some((record) => record.id === savedLayoutId)) {
      navigateWithinApp(buildPlayPath('layout'), { replace: true });
    }
  }, [location.search, navigate, previewRuntime, routeState.playMenu, savedLayouts, savedLayoutsReady]);

  useEffect(() => {
    if (!isRestrictedTopMenu(routeState.topMenu, hasAccess)) {
      return;
    }

    navigate(`${buildDocsPath(DOCS_DEFAULT_FOLDER)}${location.search}`, { replace: true });
  }, [hasAccess, location.search, navigate, routeState.topMenu]);

  useEffect(() => {
    if (routeState.topMenu !== 'plans') {
      setActivePlanQuickFilter(null);
      return;
    }

    if (routeState.planMenu === 'release') {
      setActivePlanQuickFilter('release-pending-main');
      return;
    }

    setActivePlanQuickFilter((current) => (current === 'working' || current === 'automation-failed' ? current : null));
  }, [routeState.planMenu, routeState.topMenu]);

  const gestureLayer = useMemo(
    () => ({
      id: 'main-layout',
      enabled:
        !isEReaderImmersiveActive &&
        !(isMobileViewport && routeState.topMenu === 'docs' && routeState.docsMenu === DOCS_DEFAULT_FOLDER),
      gestures: [
        {
          id: 'mobile-top-right-pull-alert',
          activeStates: ['anyway'],
          mobileOnly: true,
          trigger: 'pull-down-top-right' as const,
          onTrigger: () => {
            openSearch();
          },
        },
      ],
    }),
    [isEReaderImmersiveActive, isMobileViewport, openSearch, routeState.docsMenu, routeState.topMenu],
  );

  useGesturePageState('anyway');
  useGestureLayer(gestureLayer);

  useEffect(() => {
    const handleWindowKeyDown = (event: KeyboardEvent) => {
      if (event.repeat || isTypingTarget(event.target) || isEReaderImmersiveActive) {
        return;
      }


      if (matchesShortcut(event, appConfig.gestureShortcuts.openSearch)) {
        event.preventDefault();
        openSearch();
      }
    };

    window.addEventListener('keydown', handleWindowKeyDown);

    return () => {
      window.removeEventListener('keydown', handleWindowKeyDown);
    };
  }, [
    appConfig.gestureShortcuts.openSearch,
    isEReaderImmersiveActive,
    openSearch,
  ]);

  const selectedDocs = useMemo(
    () => docsDocuments.filter((document) => document.folder === routeState.docsMenu),
    [docsDocuments, routeState.docsMenu],
  );

  const searchOptions = useMemo(
    () =>
      buildSearchOptions({
        componentSamples,
        widgetSamples,
        docFolders,
        docsDocuments,
        savedLayouts,
        hasAccess,
        navigateTo: (path) => {
          navigateWithinApp(path);
        },
        setFocusedComponentId,
        requestPlanQuickFilter: (filter) => {
          setActivePlanQuickFilter(filter);
          setPlanQuickFilterRequestKey((previous) => previous + 1);
        },
      }),
    [
      componentSamples,
      docFolders,
      docsDocuments,
      hasAccess,
      location.search,
      navigate,
      previewRuntime,
      savedLayouts,
      setFocusedComponentId,
      widgetSamples,
    ],
  );

  useEffect(() => {
    setSearchOptions(searchOptions);
  }, [searchOptions, setSearchOptions]);

  useEffect(() => {
    setCurrentPage(
      resolveCurrentPageDescriptor({
        topMenu: routeState.topMenu,
        docsMenu: routeState.docsMenu,
        apiMenu: routeState.apiMenu,
        planMenu: routeState.planMenu,
        chatMenu: routeState.chatMenu,
        playMenu: routeState.playMenu,
        savedLayouts,
      }),
    );
  }, [routeState, savedLayouts, setCurrentPage]);

  const currentDocsFolder = docFolders.includes(routeState.docsMenu) ? routeState.docsMenu : docFolders[0] ?? DOCS_DEFAULT_FOLDER;
  const sidebarIntro = renderSidebarIntro(routeState.topMenu);
  const apiMenuItems = useMemo(() => buildApiMenuItems(), []);
  const docsMenuItems = useMemo(() => buildDocsMenuItems(docFolders), [docFolders]);
  const planMenuItems = useMemo(() => buildPlanMenuItems(hasAccess), [hasAccess]);
  const chatMenuItems = useMemo(() => buildChatMenuItems(hasAccess, chatUnreadCount), [chatUnreadCount, hasAccess]);
  const playMenuItems = useMemo(() => buildPlayMenuItems(savedLayouts), [savedLayouts]);
  const activePlayAppId = routeState.topMenu === 'play' && routeState.playMenu === 'apps'
    ? searchParams.get('app')?.trim() ?? ''
    : '';
  const isPlayAppFullscreen = activePlayAppId.length > 0;
  const initialSelectedPlanId = Number(searchParams.get('planId'));
  const initialSelectedWorkId = searchParams.get('workId');

  return (
    <MainLayoutContextProvider
      value={{
        topMenu: routeState.topMenu,
        selectedDocsMenu: routeState.docsMenu,
        selectedApiMenu: routeState.apiMenu,
        selectedPlanMenu: routeState.planMenu,
        selectedChatMenu: routeState.chatMenu,
        selectedPlayMenu: routeState.playMenu,
        activePlanQuickFilter,
        planQuickFilterRequestKey,
        initialSelectedPlanId: Number.isFinite(initialSelectedPlanId) ? initialSelectedPlanId : null,
        initialSelectedWorkId,
        selectedDocs,
        docsDocuments,
        componentSampleEntries,
        widgetSampleEntries,
        componentSamples,
        widgetSamples,
        savedLayouts,
        savedLayoutsReady,
        setSavedLayouts,
        searchOptions,
      }}
    >
      <Layout className={`app-shell app-shell--docs-api${previewRuntime ? ' app-shell--preview-runtime' : ''}`}>
        {routeState.topMenu === 'chat' || isPlayAppFullscreen ? null : <ChatRuntimeBridgeV2 />}
        {contentExpanded || isPlayAppFullscreen ? null : (
          <MainHeader
            activeTopMenu={routeState.topMenu}
            sidebarCollapsed={sidebarCollapsed}
            contentExpanded={contentExpanded}
            isMobileViewport={isMobileViewport}
            onToggleSidebar={() => {
              setSidebarCollapsed((previous) => !previous);
            }}
            onToggleContentExpanded={() => {
              setContentExpanded((previous) => !previous);
            }}
            onChangeTopMenu={(menu) => {
              navigateWithinApp(resolveTopMenuPath(menu, currentDocsFolder));
              setSidebarCollapsed(resolveSidebarCollapsedForViewport(getIsSidebarOverlayViewport(menu)));
            }}
            onOpenSearch={() => {
              openSearch();
            }}
            onOpenPlanQuickFilter={(filter) => {
              const targetPlanMenu = resolvePlanQuickFilterMenu(filter);
              setActivePlanQuickFilter(filter);
              setPlanQuickFilterRequestKey((previous) => previous + 1);
              navigateWithinApp(buildPlansPath(targetPlanMenu));
              setSidebarCollapsed(resolveSidebarCollapsedForViewport(getIsSidebarOverlayViewport('plans')));
              scrollToElement(PLAN_MENU_ANCHOR_IDS[targetPlanMenu] ?? 'plan-menu-all');
            }}
          />
        )}

        <Layout className="app-shell__body">
          {contentExpanded || isPlayAppFullscreen || (isSidebarOverlayViewport && sidebarCollapsed) ? null : (
            <MainSidebar
              activeTopMenu={routeState.topMenu}
              hasAccess={hasAccess}
              sidebarCollapsed={sidebarCollapsed}
              isMobileViewport={isMobileViewport}
              openKeys={sidebarOpenKeys}
              apiMenuItems={apiMenuItems}
              docsMenuItems={docsMenuItems}
              planMenuItems={planMenuItems}
              chatMenuItems={chatMenuItems}
              playMenuItems={playMenuItems}
              selectedApiMenu={routeState.apiMenu}
              selectedDocsMenu={routeState.docsMenu}
              selectedPlanMenu={routeState.planMenu}
              selectedChatMenu={routeState.chatMenu}
              selectedPlayMenu={routeState.playMenu}
              onOpenKeysChange={setSidebarOpenKeys}
              onSelectApiMenu={(key) => {
                navigateWithinApp(buildApisPath(key as ApiSectionKey));
                if (isSidebarOverlayViewport) {
                  setSidebarCollapsed(true);
                }
              }}
              onSelectDocsMenu={(key) => {
                navigateWithinApp(buildDocsPath(key));
                if (isSidebarOverlayViewport) {
                  setSidebarCollapsed(true);
                }
              }}
              onSelectPlanMenu={(key) => {
                setActivePlanQuickFilter(key === 'release' ? 'release-pending-main' : null);
                setPlanQuickFilterRequestKey((previous) => previous + 1);
                navigateWithinApp(buildPlansPath(key));
                if (isSidebarOverlayViewport) {
                  setSidebarCollapsed(true);
                }
              }}
              onSelectChatMenu={(key) => {
                navigateWithinApp(buildChatPath(key), { resetSearch: true });
                if (isSidebarOverlayViewport) {
                  setSidebarCollapsed(true);
                }
              }}
              onSelectPlayMenu={(key) => {
                const savedLayoutId = resolveSavedLayoutIdFromMenuKey(key);
                navigateWithinApp(savedLayoutId ? buildSavedLayoutPath(savedLayoutId) : buildPlayPath(key));
                if (isSidebarOverlayViewport) {
                  setSidebarCollapsed(true);
                }
              }}
              introColor={sidebarIntro.color}
              introTag={sidebarIntro.tag}
              introDescription={sidebarIntro.description}
            />
          )}

          <MainContent
            contentExpanded={contentExpanded}
            sidebarOverlayActive={!previewRuntime && isSidebarOverlayViewport && !sidebarCollapsed}
            disableWindowLayer={previewRuntime}
            onToggleContentExpanded={() => setContentExpanded((previous) => !previous)}
          >
            <Outlet />
          </MainContent>
        </Layout>
      </Layout>
    </MainLayoutContextProvider>
  );
}
