import React, { useCallback, useEffect, useMemo, useRef } from 'react';
import { useNavigate, useLocation } from 'react-router';
import { Layout, Menu, Button, Avatar, Badge, Dropdown, Drawer, Grid, Tooltip } from 'antd';
import { BrandLogo } from '../components/BrandLogo';
import {
  DashboardOutlined,
  TeamOutlined,
  HomeOutlined,
  SwapOutlined,
  DollarOutlined,
  FileTextOutlined,
  LogoutOutlined,
  UserOutlined,
  MenuFoldOutlined,
  MenuUnfoldOutlined,
  AppstoreOutlined,
  AuditOutlined,
  SettingOutlined,
  WalletOutlined,
  ReadOutlined,
  TagsOutlined,
  FileProtectOutlined,
  CalendarOutlined,
  SafetyOutlined,
  KeyOutlined,
  CheckCircleOutlined,
  LaptopOutlined,
  BellOutlined,
  TrophyOutlined,
  ApiOutlined,
  RobotOutlined,
  LoadingOutlined,
} from '@ant-design/icons';
import { usePermission } from '../hooks/usePermission';
import api from '../api';
import { useAppStore } from '../store/app/appStore';
import { usePermissionStore } from '../store/permission/permissionStore';
import { useUserStore } from '../store/user/userStore';
import { AUTH_STORAGE_NAME, PERMISSION_STORAGE_NAME } from '../store/middleware/persist';
import NotificationBell from '../components/NotificationBell';
import RouteDock from '../components/RouteDock';
import RouteKeeper from '../components/RouteKeeper';
import { buildMenu, type AppMenuItem } from '../auth/menu-policy';

const AiChatDrawer = React.lazy(() => import('../components/AiChat/AiChatDrawer'));

const { Header, Sider, Content } = Layout;

const iconMap: Record<string, React.ReactNode> = {
  dashboard: <DashboardOutlined />,
  calendar: <CalendarOutlined />,
  workspace: <LaptopOutlined />,
  attendance: <CheckCircleOutlined />,
  academic: <TeamOutlined />,
  students: <TeamOutlined />,
  classes: <TeamOutlined />,
  teachers: <UserOutlined />,
  exam: <TrophyOutlined />,
  home: <HomeOutlined />,
  overview: <AppstoreOutlined />,
  occupancy: <SwapOutlined />,
  expense: <DollarOutlined />,
  bill: <FileTextOutlined />,
  deposit: <WalletOutlined />,
  wallet: <WalletOutlined />,
  classroom: <ReadOutlined />,
  rental: <FileProtectOutlined />,
  organization: <TagsOutlined />,
  settings: <SettingOutlined />,
  users: <UserOutlined />,
  role: <SafetyOutlined />,
  permission: <KeyOutlined />,
  log: <AuditOutlined />,
  integration: <ApiOutlined />,
  ai: <RobotOutlined />,
  notification: <BellOutlined />,
};

const MainLayout: React.FC = () => {
  const prevPathname = useRef('');
  const navigate = useNavigate();
  const location = useLocation();
  const user = useUserStore((state) => state.user);
  const updateUser = useUserStore((state) => state.updateUser);
  const logoutUser = useUserStore((state) => state.logout);
  const collapsed = useAppStore((state) => state.sidebarCollapsed);
  const drawerOpen = useAppStore((state) => state.mobileDrawerOpen);
  const aiChatOpen = useAppStore((state) => state.aiChatOpen);
  const aiWorking = useAppStore((state) => state.aiWorking);
  const openKeys = useAppStore((state) => state.menuOpenKeys);
  const toggleSidebar = useAppStore((state) => state.toggleSidebar);
  const setDrawerOpen = useAppStore((state) => state.setMobileDrawerOpen);
  const setAiChatOpen = useAppStore((state) => state.setAiChatOpen);
  const setAiWorking = useAppStore((state) => state.setAiWorking);
  const setOpenKeys = useAppStore((state) => state.setMenuOpenKeys);
  const { permissions, hasPermission } = usePermission();

  useEffect(() => {
    let cancelled = false;
    let retryTimer: number | undefined;
    let verificationInFlight = false;

    const verifyPermissions = () => {
      if (cancelled || verificationInFlight || !useUserStore.getState().token) return;
      if (retryTimer !== undefined) {
        window.clearTimeout(retryTimer);
        retryTimer = undefined;
      }
      verificationInFlight = true;
      usePermissionStore.getState().beginPermissionVerification();
      api
        .get<{ id: number; username: string; permissions: string[]; roles?: string[] }>(
          '/auth/profile',
        )
        .then((profile) => {
          if (cancelled) return;
          verificationInFlight = false;
          usePermissionStore.getState().writePermissions(profile.permissions || []);
          updateUser(profile);
        })
        .catch(() => {
          verificationInFlight = false;
          if (cancelled || !useUserStore.getState().token) return;
          retryTimer = window.setTimeout(verifyPermissions, 5_000);
        });
    };

    const handleStorage = (event: StorageEvent) => {
      if (event.key === PERMISSION_STORAGE_NAME) {
        // 其他标签页的权限更新：原地应用，避免整页刷新造成刷新风暴。
        try {
          if (event.newValue === null) {
            usePermissionStore.getState().clearPermissions();
            return;
          }
          const parsed = JSON.parse(event.newValue) as {
            state?: { permissions?: string[] };
          };
          const permissions = parsed?.state?.permissions;
          if (Array.isArray(permissions)) {
            usePermissionStore.getState().writePermissions(permissions);
          }
        } catch {
          // 忽略无法解析的跨标签页权限写入
        }
        return;
      }
      if (event.key === AUTH_STORAGE_NAME) {
        // 仅当登录态（token）确实变化时才整页刷新：登录、退出或切换账号。
        const currentToken = useUserStore.getState().token;
        let otherToken: string | null = null;
        if (event.newValue) {
          try {
            const parsed = JSON.parse(event.newValue) as {
              state?: { token?: string | null };
            };
            otherToken = parsed?.state?.token ?? null;
          } catch {
            otherToken = null;
          }
        }
        if (otherToken === currentToken) return;
        window.location.reload();
      }
    };
    const handleOnline = () => verifyPermissions();
    const handleVisibilityChange = () => {
      if (document.visibilityState === 'visible') verifyPermissions();
    };

    verifyPermissions();
    window.addEventListener('storage', handleStorage);
    window.addEventListener('online', handleOnline);
    document.addEventListener('visibilitychange', handleVisibilityChange);
    return () => {
      cancelled = true;
      if (retryTimer !== undefined) window.clearTimeout(retryTimer);
      window.removeEventListener('storage', handleStorage);
      window.removeEventListener('online', handleOnline);
      document.removeEventListener('visibilitychange', handleVisibilityChange);
    };
  }, [updateUser]);

  const screens = Grid.useBreakpoint();
  const isMobile = !screens.sm; // < 576px (仅 xs)
  const isTablet = (screens.sm || screens.md) && !screens.lg; // 576-991px
  const isDesktop = !!screens.lg; // >= 992px
  const usesDrawer = !isDesktop;

  const menuItems = useMemo(
    () => buildMenu(user?.roles ?? [], permissions),
    [user, permissions],
  );

  const handleLogout = useCallback(() => {
    logoutUser();
    usePermissionStore.getState().clearPermissions();
    navigate('/login');
  }, [logoutUser, navigate]);

  const handleMenuClick = useCallback(
    (key: string) => {
      navigate(key);
      if (usesDrawer) setDrawerOpen(false);
    },
    [navigate, usesDrawer, setDrawerOpen],
  );

  const findSelectedKeys = useCallback(
    (items: AppMenuItem[], pathname: string): string[] => {
      for (const item of items) {
        if (item.key === pathname) return [item.key];
        if (item.children) {
          const found = findSelectedKeys(item.children, pathname);
          if (found.length > 0) return found;
        }
      }
      return [pathname];
    },
    [],
  );

  const findOpenKeys = (items: AppMenuItem[], pathname: string): string[] => {
    for (const item of items) {
      if (item.children) {
        if (
          item.children.some(
            (c) =>
              c.key === pathname || (c.children && c.children.some((gc) => gc.key === pathname)),
          )
        ) {
          return [item.key];
        }
      }
    }
    return [];
  };

  const selectedKeys = useMemo(
    () => findSelectedKeys(menuItems, location.pathname),
    [menuItems, location.pathname, findSelectedKeys],
  );
  // 路径变化时同步展开的菜单（不干扰用户手动展开/收起）
  useEffect(() => {
    if (location.pathname !== prevPathname.current) {
      prevPathname.current = location.pathname;
      const routeOpenKeys = findOpenKeys(menuItems, location.pathname);
      setOpenKeys((currentKeys) => [...new Set([...currentKeys, ...routeOpenKeys])]);
    }
  }, [location.pathname, menuItems, setOpenKeys]);

  const handleOpenChange = useCallback((keys: string[]) => {
    setOpenKeys(keys);
  }, [setOpenKeys]);

  const transformToMenuItems = useCallback((items: AppMenuItem[]): any[] => {
    return items.map((item) => ({
      key: item.key,
      icon: item.icon ? iconMap[item.icon] : undefined,
      label: item.label,
      children: item.children ? transformToMenuItems(item.children) : undefined,
    }));
  }, []);
  const menuContent = useMemo(
    () => (
      <Menu
        theme="light"
        mode="inline"
        selectedKeys={selectedKeys}
        openKeys={openKeys}
        onOpenChange={handleOpenChange}
        items={transformToMenuItems(menuItems)}
        onClick={({ key }) => handleMenuClick(key)}
        style={{ border: 'none' }}
      />
    ),
    [selectedKeys, openKeys, menuItems, handleMenuClick, handleOpenChange, transformToMenuItems],
  );

  return (
    <Layout className="app-shell" style={{ minHeight: '100vh' }}>
      {isDesktop && (
        <Sider
          trigger={null}
          collapsible
          collapsed={collapsed}
          theme="light"
          className="app-sidebar"
          style={{ background: '#fff', borderRight: '1px solid #e5e5e7' }}
        >
          <div
            style={{
              height: 64,
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              color: '#1d1d1f',
              fontSize: collapsed ? 16 : 17,
              fontWeight: 600,
              borderBottom: '1px solid #e5e5e7',
            }}
          >
            <div
              style={{
                display: 'flex',
                alignItems: 'center',
                justifyContent: 'center',
                gap: 8,
              }}
            >
              <BrandLogo size={collapsed ? 26 : 30} />
              {!collapsed && <span>学生管理系统</span>}
            </div>
          </div>
          {menuContent}
        </Sider>
      )}
      {usesDrawer && (
        <Drawer
          placement="left"
          open={drawerOpen}
          onClose={() => setDrawerOpen(false)}
          size={240}
          styles={{ body: { padding: 0 } }}
          className="app-navigation-drawer"
          title={
            <span style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
              <BrandLogo size={24} />
              学生管理系统
            </span>
          }
        >
          {menuContent}
        </Drawer>
      )}
      <Layout className="app-main" style={{ background: '#f5f5f7' }}>
        <Header
          className="app-header"
          style={{
            padding: '0 16px',
            background: '#fff',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'space-between',
            borderBottom: '1px solid #e5e5e7',
            boxShadow: 'none',
          }}
        >
          <Button
            type="text"
            aria-label={usesDrawer ? '打开菜单' : collapsed ? '展开侧边栏' : '收起侧边栏'}
            icon={
              usesDrawer ? (
                <MenuUnfoldOutlined />
              ) : collapsed ? (
                <MenuUnfoldOutlined />
              ) : (
                <MenuFoldOutlined />
              )
            }
            onClick={() => (usesDrawer ? setDrawerOpen(true) : toggleSidebar())}
          />
          <div style={{ display: 'flex', alignItems: 'center', gap: 16 }}>
            {hasPermission('ai:chat:use') && (
              <Tooltip title={aiWorking ? 'AI 处理中' : 'AI 助理'}>
                <Badge dot={aiWorking} color="#007AFF" offset={[-3, 5]}>
                  <Button
                    type="text"
                    aria-label={aiWorking ? 'AI 助理处理中' : '打开 AI 助理'}
                    icon={
                      aiWorking ? (
                        <LoadingOutlined style={{ fontSize: 17, color: '#007AFF' }} spin />
                      ) : (
                        <RobotOutlined style={{ fontSize: 17 }} />
                      )
                    }
                    onClick={() => setAiChatOpen(true)}
                  />
                </Badge>
              </Tooltip>
            )}
            {hasPermission('notification:view') && <NotificationBell />}
            <Dropdown
              menu={{
                items: [
                  {
                    key: 'logout',
                    icon: <LogoutOutlined />,
                    label: '退出登录',
                    onClick: handleLogout,
                  },
                ],
              }}
            >
              <div
                role="button"
                tabIndex={0}
                aria-label="用户菜单"
                style={{ cursor: 'pointer', display: 'flex', alignItems: 'center', gap: 8 }}
              >
                <Avatar icon={<UserOutlined />} />
                {isDesktop && <span>{user?.name || user?.username || '用户'}</span>}
              </div>
            </Dropdown>
          </div>
        </Header>
        <RouteDock
          location={location}
          menuItems={menuItems}
          onNavigate={navigate}
          draggable={isDesktop}
        />
        <Content
          className="app-content"
          style={{
            margin: isMobile ? 8 : isTablet ? 16 : 24,
            padding: isMobile ? 12 : isTablet ? 16 : 24,
            background: '#fff',
            borderRadius: 12,
          }}
        >
          <RouteKeeper />
        </Content>
      </Layout>
      {hasPermission('ai:chat:use') && (
        <React.Suspense fallback={null}>
          <AiChatDrawer
            open={aiChatOpen}
            onClose={() => setAiChatOpen(false)}
            onRequestingChange={setAiWorking}
          />
        </React.Suspense>
      )}
    </Layout>
  );
};

export default MainLayout;
