import { useState, useCallback, useEffect, useRef } from 'react';
import { Outlet } from 'react-router-dom';
import { TopNav } from '@/components/TopNav';
import { SideNav } from '@/components/SideNav';
import { RouteErrorBoundary } from '@/components/RouteErrorBoundary';
import { useRiskStore } from '@/stores';
import { TESTIDS } from '@/utils/testids';

interface AppShellProps {
  onLogout?: () => void;
}

// 收集容器内当前可聚焦的元素，供初始聚焦与焦点循环陷阱使用。
function getFocusable(container: HTMLElement): HTMLElement[] {
  return Array.from(
    container.querySelectorAll<HTMLElement>(
      'a[href], button:not([disabled]), [tabindex]:not([tabindex="-1"])'
    )
  ).filter((el) => el.offsetParent !== null || el === document.activeElement);
}

// 仅负责布局骨架（顶栏 / 侧栏 / 内容区），不涉及路由匹配与鉴权。
export function AppShell({ onLogout }: AppShellProps) {
  const alerts = useRiskStore((s) => s.alerts);
  const [drawerOpen, setDrawerOpen] = useState(false);
  // 提升手风琴展开态：导轨与抽屉两份 SideNav 共享，保持同步。
  const [expandedNav, setExpandedNav] = useState<string | null>('monitoring');
  const drawerRef = useRef<HTMLElement>(null);

  const openDrawer = useCallback(() => setDrawerOpen(true), []);
  const closeDrawer = useCallback(() => setDrawerOpen(false), []);

  // 抽屉作为模态：ESC 关闭、锁定 body 滚动、焦点移入并在关闭后归还给汉堡。
  useEffect(() => {
    if (!drawerOpen) return;

    const opener = document.activeElement as HTMLElement | null;

    // 锁定 body 滚动，关闭时还原原值。
    const prevOverflow = document.body.style.overflow;
    document.body.style.overflow = 'hidden';

    // 焦点移入抽屉（优先第一个可聚焦元素，否则聚焦抽屉容器本身）。
    const drawer = drawerRef.current;
    const focusables = drawer ? getFocusable(drawer) : [];
    (focusables[0] ?? drawer)?.focus();

    const onKeyDown = (e: KeyboardEvent) => {
      if (e.key === 'Escape') {
        e.preventDefault();
        closeDrawer();
        return;
      }
      // 焦点循环陷阱：Tab 在抽屉内首尾元素之间循环。
      if (e.key === 'Tab' && drawer) {
        const items = getFocusable(drawer);
        if (items.length === 0) {
          e.preventDefault();
          drawer.focus();
          return;
        }
        const first = items[0];
        const last = items[items.length - 1];
        const active = document.activeElement;
        if (e.shiftKey && (active === first || active === drawer)) {
          e.preventDefault();
          last.focus();
        } else if (!e.shiftKey && active === last) {
          e.preventDefault();
          first.focus();
        }
      }
    };

    document.addEventListener('keydown', onKeyDown);

    return () => {
      document.removeEventListener('keydown', onKeyDown);
      document.body.style.overflow = prevOverflow;
      // 关闭后把焦点还给打开抽屉的元素（汉堡按钮），回退到按 testid 查询。
      const restoreTarget =
        opener ??
        document.querySelector<HTMLElement>(`[data-testid="${TESTIDS.hamburger}"]`);
      restoreTarget?.focus();
    };
  }, [drawerOpen, closeDrawer]);

  return (
    <div data-testid={TESTIDS.appShell} className="h-screen bg-bg-page flex flex-col overflow-hidden">
      <TopNav onLogout={onLogout} onToggleMenu={openDrawer} isMenuOpen={drawerOpen} />

      <div className="flex flex-1 min-h-0">
        {/* lg 及以上：持久侧栏导轨 */}
        <aside
          data-testid={TESTIDS.sidebarRail}
          className="hidden lg:block w-[200px] shrink-0 bg-bg-card border-r border-border"
        >
          <SideNav
            alertCount={alerts.length}
            expanded={expandedNav}
            onExpandedChange={setExpandedNav}
          />
        </aside>

        {/* lg 以下：离屏抽屉 + 遮罩 */}
        {drawerOpen && (
          <div
            className="fixed inset-0 z-40 bg-black/40 lg:hidden"
            onClick={closeDrawer}
            aria-hidden="true"
          />
        )}
        <aside
          ref={drawerRef}
          id="app-drawer"
          role="dialog"
          aria-modal="true"
          aria-label="导航菜单"
          tabIndex={-1}
          data-testid={TESTIDS.appDrawer}
          className={`fixed top-0 left-0 bottom-0 z-50 w-[260px] max-w-[80vw] bg-bg-card border-r border-border shadow-xl transition-transform duration-200 lg:hidden ${
            drawerOpen ? 'translate-x-0' : '-translate-x-full'
          }`}
        >
          <SideNav
            alertCount={alerts.length}
            onNavigate={closeDrawer}
            expanded={expandedNav}
            onExpandedChange={setExpandedNav}
          />
        </aside>

        <main className="flex-1 min-w-0 overflow-auto p-5">
          <RouteErrorBoundary>
            <Outlet />
          </RouteErrorBoundary>
        </main>
      </div>
    </div>
  );
}
