/**
 * Virtualized block list using @tanstack/react-virtual.
 * Efficiently renders large lists by only mounting visible rows.
 */

import { useRef, useCallback } from 'react';
import { useVirtualizer } from '@tanstack/react-virtual';
import { Link } from 'react-router-dom';
import { Box, Clock, FileText, Sparkles, Loader2 } from 'lucide-react';
import type { ExplorerBlock } from '../lib/types';
import { truncateHash, formatRelativeTime, cn } from '../lib/utils';

interface VirtualBlockListProps {
  blocks: ExplorerBlock[];
  hasMore?: boolean;
  isLoadingMore?: boolean;
  onLoadMore?: () => void;
  highlightHash?: string | null;
  estimatedRowHeight?: number;
  overscan?: number;
  maxHeight?: string;
}

const ROW_HEIGHT = 56; // Estimated height in pixels for each row

export default function VirtualBlockList({
  blocks,
  hasMore = false,
  isLoadingMore = false,
  onLoadMore,
  highlightHash,
  estimatedRowHeight = ROW_HEIGHT,
  overscan = 5,
  maxHeight = '600px',
}: VirtualBlockListProps) {
  const parentRef = useRef<HTMLDivElement>(null);
  const loadMoreRef = useRef<HTMLDivElement>(null);

  // Total count includes a "loader" row if we have more items to load
  const itemCount = hasMore ? blocks.length + 1 : blocks.length;

  const virtualizer = useVirtualizer({
    count: itemCount,
    getScrollElement: () => parentRef.current,
    estimateSize: () => estimatedRowHeight,
    overscan,
  });

  const items = virtualizer.getVirtualItems();

  // Check if we've scrolled near the end to trigger load more
  const handleScroll = useCallback(() => {
    if (!onLoadMore || !hasMore || isLoadingMore) return;

    const scrollElement = parentRef.current;
    if (!scrollElement) return;

    const { scrollTop, scrollHeight, clientHeight } = scrollElement;
    const scrolledToBottom = scrollHeight - scrollTop - clientHeight < 200;

    if (scrolledToBottom) {
      onLoadMore();
    }
  }, [onLoadMore, hasMore, isLoadingMore]);

  return (
    <div className="card overflow-hidden">
      <div className="card-header flex items-center justify-between">
        <h2 className="font-semibold flex items-center gap-2">
          <Box size={18} className="text-synor-400" />
          Blocks
        </h2>
        <span className="text-sm text-gray-400">
          {blocks.length.toLocaleString()} loaded
          {hasMore && ' • Scroll for more'}
        </span>
      </div>

      {/* Table header */}
      <div className="border-b border-gray-800">
        <div className="grid grid-cols-[1fr_auto_auto_auto] gap-4 px-4 py-3 text-sm text-gray-400 font-medium">
          <span>Block</span>
          <span className="hidden sm:block w-24 text-right">Blue Score</span>
          <span className="hidden md:block w-16 text-center">Txs</span>
          <span className="w-24 text-right">Time</span>
        </div>
      </div>

      {/* Virtualized scrollable area */}
      <div
        ref={parentRef}
        className="overflow-auto scrollbar-thin"
        style={{ maxHeight }}
        onScroll={handleScroll}
      >
        <div
          style={{
            height: `${virtualizer.getTotalSize()}px`,
            width: '100%',
            position: 'relative',
          }}
        >
          {items.map((virtualRow) => {
            const isLoaderRow = virtualRow.index >= blocks.length;

            if (isLoaderRow) {
              return (
                <div
                  key="loader"
                  ref={loadMoreRef}
                  style={{
                    position: 'absolute',
                    top: 0,
                    left: 0,
                    width: '100%',
                    height: `${virtualRow.size}px`,
                    transform: `translateY(${virtualRow.start}px)`,
                  }}
                  className="flex items-center justify-center py-4"
                >
                  {isLoadingMore ? (
                    <span className="flex items-center gap-2 text-sm text-gray-400">
                      <Loader2 size={16} className="animate-spin" />
                      Loading more blocks...
                    </span>
                  ) : (
                    <span className="text-sm text-gray-500">
                      Scroll to load more
                    </span>
                  )}
                </div>
              );
            }

            const block = blocks[virtualRow.index];
            const isHighlighted = block.hash === highlightHash;

            return (
              <div
                key={block.hash}
                style={{
                  position: 'absolute',
                  top: 0,
                  left: 0,
                  width: '100%',
                  height: `${virtualRow.size}px`,
                  transform: `translateY(${virtualRow.start}px)`,
                }}
                className={cn(
                  'grid grid-cols-[1fr_auto_auto_auto] gap-4 px-4 items-center border-b border-gray-800 hover:bg-gray-800/50 transition-colors',
                  isHighlighted && 'bg-synor-500/20 animate-pulse'
                )}
              >
                {/* Block hash */}
                <div className="flex items-center gap-2 min-w-0">
                  {isHighlighted && (
                    <Sparkles size={14} className="text-synor-400 animate-spin flex-shrink-0" />
                  )}
                  <div className="min-w-0">
                    <Link
                      to={`/block/${block.hash}`}
                      className={cn(
                        'font-mono text-sm hover:text-synor-300 transition-colors truncate block',
                        isHighlighted ? 'text-synor-300 font-semibold' : 'text-synor-400'
                      )}
                    >
                      {truncateHash(block.hash)}
                    </Link>
                    <div className="text-xs text-gray-500 mt-0.5 sm:hidden">
                      Blue: {block.blueScore.toLocaleString()}
                    </div>
                  </div>
                </div>

                {/* Blue score */}
                <span
                  className={cn(
                    'hidden sm:block w-24 text-right text-sm',
                    isHighlighted ? 'text-synor-300 font-semibold' : 'text-gray-300'
                  )}
                >
                  {block.blueScore.toLocaleString()}
                </span>

                {/* Transaction count */}
                <span className="hidden md:flex items-center justify-center gap-1 w-16 text-sm text-gray-400">
                  <FileText size={14} />
                  {block.transactionCount}
                </span>

                {/* Timestamp */}
                <span className="flex items-center justify-end gap-1 w-24 text-sm text-gray-400">
                  <Clock size={14} />
                  {formatRelativeTime(block.timestamp)}
                </span>
              </div>
            );
          })}
        </div>
      </div>

      {/* Empty state */}
      {blocks.length === 0 && !isLoadingMore && (
        <div className="p-8 text-center text-gray-500">
          No blocks found
        </div>
      )}
    </div>
  );
}

export function VirtualBlockListSkeleton() {
  return (
    <div className="card overflow-hidden animate-pulse">
      <div className="card-header flex items-center justify-between">
        <div className="h-5 w-20 bg-gray-800 rounded" />
        <div className="h-4 w-32 bg-gray-800 rounded" />
      </div>
      <div className="border-b border-gray-800 px-4 py-3">
        <div className="h-4 w-full bg-gray-800/50 rounded" />
      </div>
      <div className="divide-y divide-gray-800">
        {Array.from({ length: 10 }).map((_, i) => (
          <div key={i} className="px-4 py-3 flex items-center justify-between">
            <div className="h-4 w-32 bg-gray-800 rounded" />
            <div className="h-4 w-16 bg-gray-800 rounded hidden sm:block" />
            <div className="h-4 w-12 bg-gray-800 rounded" />
          </div>
        ))}
      </div>
    </div>
  );
}
