import { useMemo, useRef } from 'react';
import { useLocation } from 'react-router';
import { useDock, MusicPlayerHost, usePanelFullscreen } from 'officerdev';
import { useCapabilities } from 'hooks/useCapabilities';
import { ErrorBoundary } from '@/components/ErrorBoundary';
import { ScreenErrorFallback } from './ScreenErrorFallback';
import { Background } from './Background';
import { Header } from './Header';
import { Dock, CORE_DOCK_ITEMS, dockItemsFromPlugins, DEFAULT_DOCK_PATHS } from './Dock';
import { useIsTouch } from './useIsTouch';
import { usePageTitleSync } from '@/state/usePageTitle';
import { RouteGate } from './RouteGate';

type DashboardLayoutProps = {
  children?: React.ReactNode;
};
export function DashboardLayout({ children }: DashboardLayoutProps) {
  const { canVisit, plugins } = useCapabilities();
  // Filtered BEFORE useDock, so a member's saved dock order cannot resurrect an icon their role no longer
  // reaches, and so the pinned-item defaults fall back to something they can actually open. Cosmetic
  // either way — every one of these routes is refused server-side too — but an app that offers a door it
  // will then slam is worse than one that never showed it.
  // The shell's own items plus whatever the installed sidecars contribute. `plugins` already excludes
  // anything uninstalled or disabled, so an absent feature has no tile at all rather than a dead one.
  const permitted = useMemo(
    () => [...CORE_DOCK_ITEMS, ...dockItemsFromPlugins(plugins)].filter((item) => canVisit(item.to)),
    [canVisit, plugins],
  );
  const { items: visibleItems } = useDock(permitted, DEFAULT_DOCK_PATHS);
  const isTouch = useIsTouch();
  const { pathname } = useLocation();
  usePageTitleSync();
  // A panel can maximize into the content region on its own, but it cannot paint over this header — the
  // region below is an `absolute z-2` stacking context and the header is a `fixed z-10` sibling of it. So
  // "full screen" is cooperative: the panel asks, and the chrome steps aside.
  const panelFullscreen = usePanelFullscreen();
  // The content region shrinks when the (in-flow) music dock takes its space; the nav dock measures its
  // reveal boundary from this element, so it always sits just above whatever's at the bottom.
  const regionRef = useRef<HTMLElement | null>(null);

  return (
    <div className="relative flex h-dvh flex-col overflow-hidden outline-none inset-0">
      <Header dockItems={visibleItems} hidden={panelFullscreen} />
      {/* overflow-CLIP, not hidden: `hidden` still makes this a scroll container, and the nav Dock —
          absolute, parked below the bottom edge by translateY while hidden — adds its transformed box to
          the scrollable overflow. So clicking a link let the browser scroll this section ~70px to reveal
          the focused element: content slid up under the fixed header and the hidden dock slid into view.
          `clip` clips identically but is not scrollable, so nothing can ever scroll it. */}
      <section ref={regionRef} className="relative min-h-0 flex-1 snap-start overflow-clip">
        <Background />
        {!isTouch && <Dock items={visibleItems} boundaryRef={regionRef} className="hidden md:flex" />}
        <div className="absolute inset-0 z-2 pt-[52px] md:pt-[64px] pb-2 overflow-y-auto">
          {/* Chrome stays outside: whatever broke, the dock and the header still navigate you off it.
              Keyed on the pathname so leaving a broken screen is itself a recovery. */}
          <ErrorBoundary
            resetKeys={[pathname]}
            fallback={({ error, reset }) => <ScreenErrorFallback error={error} reset={reset} />}
          >
            {/* Inside the boundary and around every screen, so one place decides whether a route exists for
                this account on this server. Filtering the dock was never enough: the tile was hidden and the
                route still rendered for anyone who typed it, followed an old link or restored a tab. */}
            <RouteGate>{children}</RouteGate>
          </ErrorBoundary>
        </div>
      </section>
      <MusicPlayerHost />
    </div>
  );
}
