import { useRef, useEffect, useCallback, useState } from "react";
import { useVirtualizer } from "@tanstack/react-virtual";
import { useChatMessages } from "../hooks/useChatMessages";
import { useChatPanel } from "../context/ChatPanelContext";
import { ChatMessage } from "./ChatMessage";
import { ArrowDown } from "lucide-react";
import { Button } from "@/components/ui/button";
import { Skeleton } from "@/components/ui/skeleton";
import type { ChatMessage as ChatMessageType, AgentRole } from "@paperclipai/shared";

interface ChatMessageListProps {
  conversationId: string;
  streamingContent?: string;
  isStreaming?: boolean;
  streamingAgentName?: string | null;
  streamingAgentIcon?: string | null;
  streamingAgentRole?: AgentRole | null;
  onEdit?: (messageId: string, newContent: string) => void;
  onRetry?: (messageId: string) => void;
  onHandoff?: (spec: { what: string; why: string; constraints: string; success: string }) => void;
  agentMap?: Map<string, { name: string; icon: string | null; role: AgentRole | null }>;
  onBookmark?: (messageId: string) => void;
  bookmarkedMessageIds?: Set<string>;
}

export function ChatMessageList({
  conversationId,
  streamingContent,
  isStreaming,
  streamingAgentName,
  streamingAgentIcon,
  streamingAgentRole,
  onEdit,
  onRetry,
  onHandoff,
  agentMap,
  onBookmark,
  bookmarkedMessageIds,
}: ChatMessageListProps) {
  const { messages, isLoading } = useChatMessages(conversationId);
  const { scrollToMessageId, setScrollToMessageId } = useChatPanel();
  const parentRef = useRef<HTMLDivElement>(null);
  const [showJumpToBottom, setShowJumpToBottom] = useState(false);

  // Build display list: real messages + optional synthetic streaming message
  const displayMessages: Array<ChatMessageType & { isStreamingEntry?: boolean }> = [
    ...messages,
    ...(isStreaming && streamingContent
      ? [{
          id: "__streaming__",
          conversationId,
          role: "assistant" as const,
          content: streamingContent,
          agentId: null,
          messageType: null,
          createdAt: new Date().toISOString(),
          updatedAt: null,
          isStreamingEntry: true,
        }]
      : []),
  ];

  const virtualizer = useVirtualizer({
    count: displayMessages.length,
    getScrollElement: () => parentRef.current,
    estimateSize: () => 80,
    overscan: 5,
    measureElement: (el) => el.getBoundingClientRect().height,
  });

  // Auto-scroll to bottom when new messages arrive (if user hasn't scrolled up)
  useEffect(() => {
    if (displayMessages.length > 0 && !showJumpToBottom) {
      virtualizer.scrollToIndex(displayMessages.length - 1, { align: "end" });
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [displayMessages.length]);

  // Re-measure streaming message as it grows (Pitfall 3 from RESEARCH.md)
  useEffect(() => {
    if (isStreaming && displayMessages.length > 0) {
      virtualizer.measure();
    }
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [streamingContent, isStreaming]);

  // Scroll to a specific message when scrollToMessageId is set
  useEffect(() => {
    if (!scrollToMessageId) return;
    const index = displayMessages.findIndex((m) => m.id === scrollToMessageId);
    if (index >= 0) {
      virtualizer.scrollToIndex(index, { align: "center" });
      setScrollToMessageId(null);
    }
    // TODO: if message not in current page (infinite scroll), scroll is best-effort only.
    // Future iteration: load pages until message found, then scroll.
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [scrollToMessageId]);

  // Track scroll position for "jump to bottom" button
  const handleScroll = useCallback(() => {
    const el = parentRef.current;
    if (!el) return;
    const distFromBottom = el.scrollHeight - el.scrollTop - el.clientHeight;
    setShowJumpToBottom(distFromBottom > 200);
  }, []);

  const jumpToBottom = () => {
    virtualizer.scrollToIndex(displayMessages.length - 1, { align: "end" });
    setShowJumpToBottom(false);
  };

  if (isLoading) {
    return (
      <div className="space-y-4 p-3">
        <Skeleton className="h-16 w-3/4" />
        <Skeleton className="h-12 w-1/2 ml-auto" />
        <Skeleton className="h-20 w-3/4" />
      </div>
    );
  }

  if (displayMessages.length === 0) {
    return (
      <div className="flex items-center justify-center h-full">
        <p className="text-sm text-muted-foreground">Send a message to start this conversation.</p>
      </div>
    );
  }

  return (
    <div className="relative flex-1">
      <div
        ref={parentRef}
        className="h-full overflow-auto p-3"
        onScroll={handleScroll}
      >
        <div
          style={{
            height: `${virtualizer.getTotalSize()}px`,
            position: "relative",
            width: "100%",
          }}
        >
          {virtualizer.getVirtualItems().map((item) => {
            const msg = displayMessages[item.index]!;
            const agent = msg.agentId && agentMap ? agentMap.get(msg.agentId) : undefined;
            const isThisStreaming = "isStreamingEntry" in msg && msg.isStreamingEntry;

            return (
              <div
                key={item.key}
                data-index={item.index}
                ref={virtualizer.measureElement}
                style={{
                  position: "absolute",
                  top: 0,
                  transform: `translateY(${item.start}px)`,
                  width: "100%",
                  paddingBottom: "16px",
                }}
              >
                <ChatMessage
                  id={msg.id}
                  role={msg.role as "user" | "assistant" | "system"}
                  content={msg.content}
                  messageType={msg.messageType}
                  conversationId={conversationId}
                  agentName={agent?.name ?? streamingAgentName}
                  agentIcon={agent?.icon ?? streamingAgentIcon}
                  agentRole={agent?.role ?? streamingAgentRole}
                  timestamp={msg.createdAt}
                  isStreaming={isThisStreaming}
                  isAnyStreaming={isStreaming}
                  onEdit={onEdit}
                  onRetry={onRetry}
                  onHandoff={onHandoff}
                  onBookmark={onBookmark}
                  isBookmarked={msg.id ? (bookmarkedMessageIds?.has(msg.id) ?? false) : false}
                  files={msg.files}
                />
              </div>
            );
          })}
        </div>
      </div>

      {/* Jump to bottom button */}
      {showJumpToBottom && (
        <div className="absolute bottom-2 right-4">
          <Button
            variant="outline"
            size="icon"
            className="h-8 w-8 rounded-full shadow-md"
            onClick={jumpToBottom}
            aria-label="Scroll to latest message"
          >
            <ArrowDown className="h-4 w-4" />
          </Button>
        </div>
      )}
    </div>
  );
}
