import { useEffect, useLayoutEffect, useRef, useState, useCallback, useMemo } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
import { MessageBubble } from './MessageBubble';
import type { ChatMessage } from '../../types/protocol';
import { Sparkles, ArrowDown, ArrowUp } from 'lucide-react';

interface MessageListProps {
  messages: ChatMessage[];
  onNavigateToSubAgent?: (taskId: string, description: string, subagentType?: string) => void;
  showThinking?: boolean;
  /** 视图标识，用于保存/恢复滚动位置。不同视图间切换时保持各自的滚动位置。 */
  viewKey?: string;
  /** 高亮的消息 ID，点击待办项后滚动并高亮显示 */
  highlightedMessageId?: string | null;
  /** 主代理当前生效模型（透传给 MessageBubble 做 Task 卡片差异显示） */
  effectiveModel?: { provider: string; model: string } | null;
}

export function MessageList({
  messages,
  onNavigateToSubAgent,
  showThinking = true,
  viewKey,
  highlightedMessageId,
  effectiveModel,
}: MessageListProps) {
  const containerRef = useRef<HTMLDivElement>(null);
  const isAtBottomRef = useRef(true);
  const prevShowBottomRef = useRef(false);
  const prevViewKeyRef = useRef(viewKey);
  const viewKeyRef = useRef(viewKey);
  viewKeyRef.current = viewKey;

  // 追踪上次的消息条数，用于计算真正新增的消息数（而非 messages 引用变化次数）。
  // 流式输出时每个 delta 都会产生新的 messages 数组引用，但消息条数不变，
  // 不应计入 newMessageCount。
  const prevMessageCountRef = useRef(messages.length);

  // Per-view scroll position memory
  const scrollPositionsRef = useRef<Map<string, number>>(new Map());

  const [showScrollToBottom, setShowScrollToBottom] = useState(false);
  const [newMessageCount, setNewMessageCount] = useState(0);

  // 虚拟化列表：只渲染视口内的消息，长对话不卡顿。
  // 动态测量元素高度（消息内容长度差异大），overscan 保证滚动平滑。
  const virtualizer = useVirtualizer({
    count: messages.length,
    getScrollElement: () => containerRef.current,
    estimateSize: () => 120,
    overscan: 6,
    measureElement:
      typeof window !== 'undefined' && navigator.userAgent.includes('Firefox')
        ? (el) => el.getBoundingClientRect().height
        : undefined,
  });

  // 消息 id → virtualizer index 映射，用于 highlight 滚动定位。
  // useMemo 化：仅在 messages 变化时重建，而非每次渲染（流式期间每帧一次）都全量重建。
  const messageIdToIndex = useMemo(() => {
    const map = new Map<string, number>();
    messages.forEach((m, i) => map.set(m.id, i));
    return map;
  }, [messages]);

  // ---- scroll helpers ----

  const scrollToBottom = useCallback(
    (behavior: ScrollBehavior = 'smooth') => {
      isAtBottomRef.current = true;
      setShowScrollToBottom(false);
      setNewMessageCount(0);
      if (messages.length > 0) {
        virtualizer.scrollToIndex(messages.length - 1, { align: 'end', behavior });
      }
    },
    [virtualizer, messages.length],
  );

  const scrollToTop = useCallback(() => {
    containerRef.current?.scrollTo({ top: 0, behavior: 'smooth' });
  }, []);

  // ---- scroll event: track whether user is at bottom ----

  const handleScroll = useCallback(() => {
    const el = containerRef.current;
    if (!el) return;

    const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
    const nearBottom = distanceFromBottom < 120;

    // Save scroll position for current view
    const key = viewKeyRef.current;
    if (key) {
      scrollPositionsRef.current.set(key, el.scrollTop);
    }

    isAtBottomRef.current = nearBottom;

    // 回到底部：距底部 > 200px 时显示（同时显示回到顶部）
    const shouldShowBottom = distanceFromBottom > 200;
    if (shouldShowBottom !== prevShowBottomRef.current) {
      prevShowBottomRef.current = shouldShowBottom;
      setShowScrollToBottom(shouldShowBottom);
    }

    // 滚回底部时清除新消息计数
    if (nearBottom) {
      setNewMessageCount(0);
    }
  }, []);

  // ---- auto-scroll: handle view switches and message updates ----

  useLayoutEffect(() => {
    const prevKey = prevViewKeyRef.current;
    const viewChanged = prevKey !== viewKey;
    prevViewKeyRef.current = viewKey;

    if (messages.length === 0) {
      isAtBottomRef.current = true;
      prevMessageCountRef.current = 0;
      return;
    }

    if (viewChanged) {
      // View switched (e.g. breadcrumb navigation): restore saved scroll position
      prevMessageCountRef.current = messages.length;
      const key = viewKey ?? '';
      const savedPos = scrollPositionsRef.current.get(key);
      if (savedPos !== undefined && containerRef.current) {
        containerRef.current.scrollTop = savedPos;
        const el = containerRef.current;
        const distanceFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
        isAtBottomRef.current = distanceFromBottom < 120;
        return;
      }
      // First time viewing this view: scroll to bottom
      isAtBottomRef.current = true;
      virtualizer.scrollToIndex(messages.length - 1, { align: 'end', behavior: 'instant' });
      return;
    }

    // Same view, messages changed: normal auto-scroll logic
    const lastMessage = messages[messages.length - 1];
    const newCount = messages.length - prevMessageCountRef.current;
    prevMessageCountRef.current = messages.length;

    if (lastMessage.role === 'user' || isAtBottomRef.current) {
      virtualizer.scrollToIndex(messages.length - 1, { align: 'end', behavior: 'instant' });
      // 用户自己发消息或已在底部时，不需要计数
      if (newCount > 0) {
        setNewMessageCount(0);
      }
    } else if (newCount > 0) {
      // 只有真正新增了消息条数时才累加（流式 delta 不增加条数，不计数）
      setNewMessageCount((prev) => prev + newCount);
    }
  }, [messages, viewKey, virtualizer]);

  // ---- mount: always scroll to bottom if messages already loaded ----

  useEffect(() => {
    if (messages.length > 0) {
      scrollToBottom('instant');
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // ---- highlight and scroll to todo message ----

  useEffect(() => {
    if (!highlightedMessageId) return;
    const idx = messageIdToIndex.get(highlightedMessageId);
    if (idx === undefined) return;

    virtualizer.scrollToIndex(idx, { align: 'center', behavior: 'smooth' });

    // 高亮 class 需等 DOM 渲染后操作
    requestAnimationFrame(() => {
      const container = containerRef.current;
      if (!container) return;
      const targetElement = container.querySelector(`[data-message-id="${highlightedMessageId}"]`);
      if (!targetElement) return;
      targetElement.classList.add('todo-highlight');
      setTimeout(() => {
        targetElement.classList.remove('todo-highlight');
      }, 2000);
    });
  }, [highlightedMessageId, messageIdToIndex, virtualizer]);

  // ---- 行高强制重测（修复 tanstack virtual-core 3.17.x 陈旧高度导致行重叠）----
  // 3.17.x 在滚动状态会跳过同步测量、对缓冲区外的行跳过 RO 更新并复用缓存高度；
  // 滚动停止后或对话列宽度变化（拖拽调宽/折叠侧栏）时，换行行可能保留 120px 估值导致行重叠。
  // 在这两个时机绕过门控，直接对已渲染行调用 resizeItem 强制纠正。
  const remeasureRows = useCallback(() => {
    const container = containerRef.current;
    if (!container) return;
    for (const vi of virtualizer.getVirtualItems()) {
      const node = container.querySelector<HTMLElement>(`[data-index="${vi.index}"]`);
      if (node) {
        const h = Math.round(node.getBoundingClientRect().height);
        if (h > 0) virtualizer.resizeItem(vi.index, h);
      }
    }
  }, [virtualizer]);

  // 宽度变化后强制重测（含一次 rAF 补测同提交内的重 stamped 行）
  useEffect(() => {
    const container = containerRef.current;
    if (!container || typeof ResizeObserver === 'undefined') return;
    let lastWidth = container.clientWidth;
    const ro = new ResizeObserver(() => {
      const w = container.clientWidth;
      if (w === lastWidth) return;
      lastWidth = w;
      remeasureRows();
      requestAnimationFrame(remeasureRows);
    });
    ro.observe(container);
    return () => ro.disconnect();
  }, [virtualizer, remeasureRows]);

  // 滚动停止后补测一次（滚动期间被门控跳过的行在此纠正）
  const isScrolling = virtualizer.isScrolling;
  useEffect(() => {
    if (isScrolling) return;
    const id = requestAnimationFrame(remeasureRows);
    return () => cancelAnimationFrame(id);
  }, [isScrolling, remeasureRows]);

  // ---- empty state ----

  if (messages.length === 0) {
    return (
      <div className="flex h-full items-center justify-center">
        <div className="text-center animate-fade-in">
          <div className="mb-6 inline-flex h-16 w-16 items-center justify-center rounded-2xl border border-[var(--border-color)] bg-[var(--bg-tertiary)]">
            <Sparkles className="h-8 w-8 text-[var(--accent-cyan)]" />
          </div>
          <h2 className="mb-2 text-xl font-semibold text-[var(--text-primary)]">开始新的对话</h2>
          <p className="text-sm text-[var(--text-muted)]">在下方输入消息开始与 AI 助手聊天</p>
        </div>
      </div>
    );
  }

  // ---- main render ----

  const virtualItems = virtualizer.getVirtualItems();
  const totalSize = virtualizer.getTotalSize();

  return (
    <div className="relative h-full">
      <div ref={containerRef} onScroll={handleScroll} className="h-full overflow-y-auto p-6">
        {/* 虚拟化容器：总高度撑开滚动条，子项绝对定位 */}
        <div style={{ height: `${totalSize}px`, position: 'relative' }}>
          {virtualItems.map((vi) => {
            const message = messages[vi.index];
            return (
              <div
                key={message.id}
                data-index={vi.index}
                data-message-id={message.id}
                ref={virtualizer.measureElement}
                className="pb-6"
                style={{
                  position: 'absolute',
                  top: 0,
                  left: 0,
                  width: '100%',
                  transform: `translateY(${vi.start}px)`,
                }}
              >
                <div className="mx-auto w-full max-w-[736px]">
                  <MessageBubble
                    message={message}
                    onNavigateToSubAgent={onNavigateToSubAgent}
                    showThinking={showThinking}
                    effectiveModel={effectiveModel}
                  />
                </div>
              </div>
            );
          })}
        </div>
      </div>

      {/* 浮动导航按钮 — 底部居中并排 */}
      {showScrollToBottom && (
        <div className="absolute bottom-4 left-1/2 -translate-x-1/2 z-10 flex items-center gap-2">
          {/* 回到顶部 */}
          <button
            onClick={scrollToTop}
            className="flex items-center gap-1.5 px-3 py-2 rounded-full
                       bg-[var(--bg-tertiary)]/90 backdrop-blur-md
                       border border-[var(--border-color)] shadow-sm
                       text-[var(--text-muted)] hover:text-[var(--text-primary)]
                       transition-colors duration-200 ease-out
                       animate-fade-in"
            aria-label="回到顶部"
          >
            <ArrowUp className="h-4 w-4" />
            <span className="text-sm text-[var(--text-secondary)]">顶部</span>
          </button>

          {/* 回到底部 */}
          <button
            onClick={() => scrollToBottom('smooth')}
            className="flex items-center gap-2 px-4 py-2 rounded-full
                       bg-[var(--bg-tertiary)]/90 backdrop-blur-md
                       border border-[var(--border-color)] shadow-sm
                       text-[var(--text-muted)] hover:text-[var(--text-primary)]
                       transition-colors duration-200 ease-out
                       animate-fade-in"
            aria-label="回到底部"
          >
            <ArrowDown
              className={`h-4 w-4 transition-transform duration-300 ${newMessageCount > 0 ? 'animate-bounce' : ''}`}
            />
            {newMessageCount > 0 ? (
              <span className="text-sm font-medium text-[var(--text-primary)]">
                {newMessageCount} 条新消息
              </span>
            ) : (
              <span className="text-sm text-[var(--text-secondary)]">回到最新</span>
            )}
            {newMessageCount > 0 && (
              <span className="relative flex h-2 w-2">
                <span className="absolute inline-flex h-full w-full animate-ping rounded-full bg-[var(--accent-cyan)]/60" />
                <span className="relative inline-flex h-2 w-2 rounded-full bg-[var(--accent-cyan)]" />
              </span>
            )}
          </button>
        </div>
      )}
    </div>
  );
}
