import React, { useEffect, useMemo, useState } from 'react';
import type { DragEndEvent } from '@dnd-kit/core';
import { closestCenter, DndContext, PointerSensor, useSensor, useSensors } from '@dnd-kit/core';
import {
  arrayMove,
  horizontalListSortingStrategy,
  SortableContext,
  useSortable,
} from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import { Tabs } from 'antd';
import type { TabsProps } from 'antd';
import type { Location } from 'react-router-dom';
import type { AppMenuItem } from '../../auth/menu-policy';

const STORAGE_KEY = 'gongxue-route-dock';

interface DockTab {
  key: string;
  label: string;
}

interface RouteDockProps {
  location: Location;
  menuItems: readonly AppMenuItem[];
  onNavigate: (path: string) => void;
  draggable: boolean;
}

interface DraggableTabNodeProps extends React.HTMLAttributes<HTMLDivElement> {
  'data-node-key': string;
}

function findMenuLabel(items: readonly AppMenuItem[], pathname: string): string | undefined {
  for (const item of items) {
    if (item.key === pathname) return item.label;
    if (item.children) {
      const label = findMenuLabel(item.children, pathname);
      if (label) return label;
    }
  }
  return undefined;
}

function getRouteLabel(items: readonly AppMenuItem[], pathname: string): string {
  const menuLabel = findMenuLabel(items, pathname);
  if (menuLabel) return menuLabel;
  if (/^\/students\/\d+\/profile$/.test(pathname)) return '学生档案';
  if (/^\/classes\/\d+$/.test(pathname)) return '班级详情';
  return pathname === '/' ? '首页' : '页面';
}

function readStoredTabs(): DockTab[] {
  try {
    const parsed = JSON.parse(localStorage.getItem(STORAGE_KEY) || '[]');
    if (!Array.isArray(parsed)) return [];
    return parsed.filter(
      (tab): tab is DockTab =>
        typeof tab?.key === 'string' && tab.key.startsWith('/') && typeof tab?.label === 'string',
    );
  } catch {
    return [];
  }
}

const DraggableTabNode: React.FC<Readonly<DraggableTabNodeProps>> = ({ ...props }) => {
  const { attributes, listeners, setNodeRef, transform, transition, isDragging } = useSortable({
    id: props['data-node-key'],
  });
  const child = props.children as React.ReactElement<{ style?: React.CSSProperties }>;

  return React.cloneElement(child, {
    ref: setNodeRef,
    style: {
      ...child.props.style,
      transform: CSS.Translate.toString(transform),
      transition,
      cursor: isDragging ? 'grabbing' : 'grab',
      zIndex: isDragging ? 1 : undefined,
      opacity: isDragging ? 0.92 : undefined,
      boxShadow: isDragging ? '0 8px 20px rgba(29, 29, 31, 0.14)' : undefined,
    },
    ...attributes,
    ...listeners,
  } as React.HTMLAttributes<HTMLElement>);
};

const RouteDock: React.FC<RouteDockProps> = ({ location, menuItems, onNavigate, draggable }) => {
  const activeKey = `${location.pathname}${location.search}`;
  const [tabs, setTabs] = useState<DockTab[]>(() => {
    const storedTabs = readStoredTabs();
    if (location.pathname === '/') return storedTabs;
    if (storedTabs.some((tab) => tab.key === activeKey)) return storedTabs;
    return [...storedTabs, { key: activeKey, label: getRouteLabel(menuItems, location.pathname) }];
  });
  const sensors = useSensors(useSensor(PointerSensor, { activationConstraint: { distance: 8 } }));

  useEffect(() => {
    if (location.pathname === '/') return;
    setTabs((currentTabs) => {
      const label = getRouteLabel(menuItems, location.pathname);
      const existing = currentTabs.find((tab) => tab.key === activeKey);
      if (!existing) return [...currentTabs, { key: activeKey, label }];
      if (existing.label === label) return currentTabs;
      return currentTabs.map((tab) => (tab.key === activeKey ? { ...tab, label } : tab));
    });
  }, [activeKey, location.pathname, menuItems]);

  useEffect(() => {
    localStorage.setItem(STORAGE_KEY, JSON.stringify(tabs));
  }, [tabs]);

  const tabItems = useMemo<NonNullable<TabsProps['items']>>(
    () =>
      tabs.map((tab) => ({
        key: tab.key,
        label: tab.label,
        closable: tabs.length > 1,
      })),
    [tabs],
  );

  const closeTab = (targetKey: string) => {
    const targetIndex = tabs.findIndex((tab) => tab.key === targetKey);
    if (targetIndex < 0 || tabs.length === 1) return;
    const nextTabs = tabs.filter((tab) => tab.key !== targetKey);
    setTabs(nextTabs);
    if (targetKey === activeKey) {
      const nextActiveTab = nextTabs[Math.min(targetIndex, nextTabs.length - 1)];
      if (nextActiveTab) onNavigate(nextActiveTab.key);
    }
  };

  const handleDragEnd = ({ active, over }: DragEndEvent) => {
    if (!over || active.id === over.id) return;
    setTabs((currentTabs) => {
      const activeIndex = currentTabs.findIndex((tab) => tab.key === active.id);
      const overIndex = currentTabs.findIndex((tab) => tab.key === over.id);
      return activeIndex < 0 || overIndex < 0
        ? currentTabs
        : arrayMove(currentTabs, activeIndex, overIndex);
    });
  };

  const renderTabBar: TabsProps['renderTabBar'] = (tabBarProps, DefaultTabBar) => {
    const tabBar = (
      <DefaultTabBar {...tabBarProps}>
        {(node) => {
          if (!draggable) return node;
          return (
            <DraggableTabNode
              {...(node as React.ReactElement<DraggableTabNodeProps>).props}
              key={node.key}
            >
              {node}
            </DraggableTabNode>
          );
        }}
      </DefaultTabBar>
    );

    if (!draggable) return tabBar;
    return (
      <DndContext sensors={sensors} collisionDetection={closestCenter} onDragEnd={handleDragEnd}>
        <SortableContext
          items={tabs.map((tab) => tab.key)}
          strategy={horizontalListSortingStrategy}
        >
          {tabBar}
        </SortableContext>
      </DndContext>
    );
  };

  if (location.pathname === '/' || tabs.length === 0) return null;

  return (
    <nav className="route-dock" aria-label="已打开页面">
      <Tabs
        type="editable-card"
        size="small"
        hideAdd
        activeKey={activeKey}
        items={tabItems}
        animated={false}
        onChange={onNavigate}
        onEdit={(targetKey, action) => {
          if (action === 'remove') closeTab(String(targetKey));
        }}
        renderTabBar={renderTabBar}
      />
    </nav>
  );
};

export default RouteDock;
