import React, { ReactNode, Suspense, useEffect, useRef } from 'react';
import { Outlet, useLocation, useMatch, useNavigate } from 'react-router-dom';
import { ScreenSize, useScreenSizeContext } from '../../hooks/useScreenSize';
import { isNativePlatform } from '../../utils/capacitor';
import { BOTS_PATH, CHANNELS_PATH, CHANNELS_SPACE_PATH, DIRECT_PATH } from '../../pages/paths';
import { getRouteSectionParent, isListingRootPath } from '../../utils/routeParent';
import { SwipeBackOverlay } from '../swipe-back/SwipeBackOverlay';
import * as css from './style.css';

// MobileTabsPager statically imports the Channels and Bots feature modules and
// renders only on `mobile && native` (below), so lazy-loading it here keeps the
// pager glue (gesture/geometry/header) off non-native targets. NOTE: this no
// longer keeps Channels/Bots off the boot bundle — those listing tabs are now
// imported eagerly in `Router.tsx` (their lazy-split caused a web tab-switch
// flicker for ~5.6 KB gz; see `docs/ai/bugs.md`), so they ship in the entry on
// every target regardless. On native the pager chunk streams from the local APK
// filesystem (no network), so its null Suspense fallback is imperceptible.
const MobileTabsPager = React.lazy(() =>
  import('./MobileTabsPager').then((m) => ({ default: m.MobileTabsPager }))
);

// Wraps the persistent listing pager when it's serving as the BASE layer
// behind a chat overlay. Toggles `inert` (+ aria-hidden) so the whole pager
// subtree is removed from hit-testing, focus order and the a11y tree while a
// chat sits on top — same technique as `PaneSlot` in MobileTabsPager.
// `inert` is assigned via ref (not a JSX attr) because React 18.2's
// HTMLAttributes typing doesn't include it; the DOM property is supported on
// Capacitor's WebView baseline (Chromium 102+).
function BaseLayer({ inert, children }: { inert: boolean; children: ReactNode }) {
  const ref = useRef<HTMLDivElement>(null);
  useEffect(() => {
    if (ref.current) ref.current.inert = inert;
  }, [inert]);
  return (
    <div ref={ref} className={css.tabsBaseLayer} aria-hidden={inert || undefined}>
      {children}
    </div>
  );
}

// Router-level wrapper around the three listing tabs (/direct/, /channels/,
// /bots/) and their detail screens. On `mobile && native` it implements a
// native navigation-stack: the listing pager is ALWAYS mounted as the base
// layer, and a detail URL (a chat) is mounted as a sliding overlay on top of
// it. A rightward swipe pops the chat to reveal the real list behind it (see
// `SwipeBackOverlay`). At a listing root there's no overlay — just the pager,
// exactly as before, only wrapped in `tabsHost`/`BaseLayer`.
//
// Anywhere else — non-mobile breakpoints (tablet, desktop), non-Capacitor
// runtimes (mobile web, Electron) — we pass through to `<Outlet/>` and the
// existing route tree (its own PageRoot nav + Room) renders unchanged.
export function MobileTabsLayout() {
  const mobile = useScreenSizeContext() === ScreenSize.Mobile;
  const native = isNativePlatform();
  const location = useLocation();
  const navigate = useNavigate();
  // The shared CSS-var host: SwipeBackOverlay writes `--swipe-x` +
  // `data-swipe-dragging` here; the overlay card reads the inherited
  // `--swipe-x` to slide. The base layer is static (no parallax).
  const hostRef = useRef<HTMLDivElement>(null);

  // Listing roots (exact). Determine base-only vs base+overlay.
  const directRoot = !!useMatch({ path: DIRECT_PATH, end: true });
  const channelsRoot = !!useMatch({ path: CHANNELS_PATH, end: true });
  const channelsSpaceRoot = !!useMatch({ path: CHANNELS_SPACE_PATH, end: true });
  const botsRoot = !!useMatch({ path: BOTS_PATH, end: true });
  const onListingRoot = directRoot || channelsRoot || channelsSpaceRoot || botsRoot;

  // Section membership (prefix). A detail URL under one of these is a chat we
  // overlay; the pager backdrop resolves the matching tab from the section.
  const directSection = !!useMatch({ path: DIRECT_PATH, end: false });
  const channelsSection = !!useMatch({ path: CHANNELS_PATH, end: false });
  const botsSection = !!useMatch({ path: BOTS_PATH, end: false });
  const onTabsSection = directSection || channelsSection || botsSection;

  if (!(mobile && native) || !onTabsSection) {
    return <Outlet />;
  }

  const hasOverlay = !onListingRoot; // a detail URL under a tab section → a chat
  // Pop target. When it's a real listing root we run the animated card-slide;
  // when it's itself a detail screen (a thread / event-permalink whose parent
  // is the room) we skip the visual swipe and leave header/hardware back.
  const parent = getRouteSectionParent(location.pathname);
  const swipeEnabled = !!parent && isListingRootPath(parent);
  const onBack = () => {
    if (parent) navigate(parent, { replace: true });
  };

  return (
    <div ref={hostRef} className={css.tabsHost}>
      <BaseLayer inert={hasOverlay}>
        <Suspense fallback={null}>
          <MobileTabsPager asBackdrop={hasOverlay} />
        </Suspense>
      </BaseLayer>
      {hasOverlay && (
        <SwipeBackOverlay
          hostRef={hostRef}
          swipeEnabled={swipeEnabled}
          resetKey={location.key}
          onBack={onBack}
        >
          <Outlet />
        </SwipeBackOverlay>
      )}
    </div>
  );
}
