"use client";

/**
 * AppShell - MF Shell 布局容器
 *
 * 职责（02-architecture-design.md §1.2）：
 * 1. 左侧导航树（viewports GraphQL query，ARB-001 §1.2）
 * 2. 主内容区（children slot）
 * 3. 路由守卫（未登录跳转 /login）
 * 4. 用户信息 + 登出
 * 5. 按 requiredPermission 过滤视口（F7 权限点）
 *
 * 数据来源（ARB-002 §2.4 ai13 执行项 #3）：
 * - viewports: GraphQL ViewportsQuery（替代 REST /api/v1/teacher/viewports）
 * - user: GraphQL MeQuery（在 DashboardPage 已加载，AppShell 从 localStorage 兜底）
 *
 * 维护者：ai13（teacher-portal）
 */

import { useEffect, useMemo } from "react";
import { useRouter, usePathname } from "next/navigation";
import Link from "next/link";
import { useQuery } from "urql";
import { ErrorBoundary, Loading } from "@edu/ui-components";
import { usePermission } from "@edu/hooks";
import { ViewportsQuery, MeQuery } from "@/lib/graphql";
import type { ViewportItem, User } from "@/lib/graphql";
import { getToken, getUser, logout } from "@/lib/auth";
import {
  useCrossTabSync,
  broadcastCrossTabEvent,
} from "@/hooks/use-cross-tab-sync";

/**
 * 权限上下文：从 localStorage 读取（登录时由 iam 返回并存储）。
 * P3+ 改为 GraphQL me query 实时拉取（usePermission hook 接受 context props）。
 */
function buildPermissionContext(user: User | null) {
  if (!user) return null;
  // localStorage UserInfo 包含 permissions 字段（iam /iam/permissions/effective 返回）
  const stored = getUser();
  return {
    permissions: stored?.permissions ?? [],
    roles: user.roles,
    dataScope: user.dataScope,
  };
}

export default function AppShell({ children }: { children: React.ReactNode }) {
  const router = useRouter();
  const pathname = usePathname();

  // 路由守卫：未登录跳转 /login
  useEffect(() => {
    const token = getToken();
    if (!token) {
      router.replace("/login");
    }
  }, [router]);

  // 多 Tab 会话同步：监听 logout / role-change / token-refresh 事件
  useCrossTabSync();

  // GraphQL: viewports query（替代 REST /api/v1/teacher/viewports）
  const [viewportsResult] = useQuery({
    query: ViewportsQuery,
  });

  // GraphQL: me query（实时获取当前用户信息，替代 localStorage 读取）
  const [meResult] = useQuery({
    query: MeQuery,
  });

  const user = meResult.data?.me ?? null;
  const permissionContext = useMemo(
    () => buildPermissionContext(user ?? null),
    [user],
  );
  const { hasPermission } = usePermission({ context: permissionContext });

  // 按权限过滤视口（F7: requiredPermission 为 null 表示公开视口）
  const visibleViewports = useMemo(() => {
    const list: ViewportItem[] = viewportsResult.data?.viewports ?? [];
    return list.filter(
      (vp) => !vp.requiredPermission || hasPermission(vp.requiredPermission),
    );
  }, [viewportsResult, hasPermission]);

  // 视口加载中：占位（避免导航闪烁）
  if (viewportsResult.fetching && visibleViewports.length === 0) {
    return (
      <div className="min-h-screen bg-paper">
        <Loading lines={5} />
      </div>
    );
  }

  // 视口加载错误：ErrorBoundary 兜底（不阻塞主内容）
  const viewportError = viewportsResult.error ? (
    <p className="px-3 py-2 text-tiny text-danger">
      导航加载失败：{viewportsResult.error.message}
    </p>
  ) : null;

  // 退出登录：先广播给其他 Tab，再执行本地登出
  const handleLogout = () => {
    broadcastCrossTabEvent("logout");
    logout();
  };

  return (
    <div className="min-h-screen flex bg-paper">
      {/* 左侧栏：导航树 */}
      <aside className="w-56 flex-shrink-0 border-r border-rule bg-paper flex flex-col">
        <div className="px-6 py-6">
          <h1 className="text-xl font-serif text-ink">Edu</h1>
          <p className="mt-1 text-tiny text-ink-muted">教师端</p>
        </div>
        <div className="rule-thin mx-6" />

        <nav className="mt-4 px-3">
          {viewportError}
          {visibleViewports.length === 0 && !viewportError ? (
            <p className="px-3 py-2 text-tiny text-ink-muted">暂无可用视口</p>
          ) : (
            visibleViewports.map((vp) => {
              const active = pathname === vp.route;
              return (
                <Link
                  key={vp.key}
                  href={vp.route}
                  className={`block px-3 py-2 text-sm transition-colors ${
                    active
                      ? "text-accent border-l-2 border-accent font-serif"
                      : "text-ink border-l-2 border-transparent font-sans hover:text-accent"
                  }`}
                >
                  {vp.label}
                </Link>
              );
            })
          )}
        </nav>

        {/* 底部：用户信息 + 登出 */}
        <div className="mt-auto px-6 py-4 border-t border-rule">
          {user && (
            <div className="mb-2">
              <p className="text-sm text-ink">{user.name}</p>
              <p className="text-tiny text-ink-muted">
                {user.roles.join(", ") || "无角色"}
              </p>
            </div>
          )}
          <button
            onClick={handleLogout}
            className="text-tiny uppercase tracking-wide text-ink-muted hover:opacity-70"
          >
            退出登录
          </button>
        </div>
      </aside>

      {/* 中间：内容区（纸面） */}
      <main className="flex-1 overflow-auto">
        <ErrorBoundary
          fallback={(error, reset) => (
            <div
              role="alert"
              className="flex min-h-[200px] flex-col items-center justify-center gap-4 p-8"
            >
              <h2 className="text-lg font-serif text-ink">页面出错了</h2>
              <p className="text-sm text-ink-muted">{error.message}</p>
              <button
                type="button"
                onClick={reset}
                className="px-4 py-2 text-sm text-ink-on-accent bg-accent rounded-button hover:bg-accent-hover"
              >
                重试
              </button>
            </div>
          )}
        >
          {children}
        </ErrorBoundary>
      </main>
    </div>
  );
}
