import { useEffect, useRef } from 'react';

import { CSS } from '../core/constants';
import { useGriddyStore } from '../core/GriddyStore';
import styles from '../styles/griddy.module.css';
import { TableRow } from './TableRow';

export function VirtualBody() {
  const table = useGriddyStore((s) => s._table);
  const virtualizer = useGriddyStore((s) => s._virtualizer);
  const setTotalRows = useGriddyStore((s) => s.setTotalRows);
  const infiniteScroll = useGriddyStore((s) => s.infiniteScroll);

  const rows = table?.getRowModel().rows;
  const virtualRows = virtualizer?.getVirtualItems();
  const totalSize = virtualizer?.getTotalSize() ?? 0;

  // Track if we're currently loading to prevent multiple simultaneous calls
  const isLoadingRef = useRef(false);

  // Sync row count to store for keyboard navigation bounds
  useEffect(() => {
    if (rows) {
      setTotalRows(rows.length);
    }
  }, [rows?.length, setTotalRows]);

  // Infinite scroll: detect when approaching the end
  useEffect(() => {
    if (!infiniteScroll?.enabled || !infiniteScroll.onLoadMore || !virtualRows || !rows) {
      return;
    }

    const { hasMore = true, isLoading = false, threshold = 10 } = infiniteScroll;

    // Don't trigger if already loading or no more data
    if (isLoading || !hasMore || isLoadingRef.current) {
      return;
    }

    // Check if the last rendered virtual row is within threshold of the end
    const lastVirtualRow = virtualRows[virtualRows.length - 1];
    if (!lastVirtualRow) return;

    const lastVirtualIndex = lastVirtualRow.index;
    const totalRows = rows.length;
    const distanceFromEnd = totalRows - lastVirtualIndex - 1;

    if (distanceFromEnd <= threshold) {
      isLoadingRef.current = true;
      const loadPromise = infiniteScroll.onLoadMore();

      if (loadPromise instanceof Promise) {
        loadPromise.finally(() => {
          isLoadingRef.current = false;
        });
      } else {
        isLoadingRef.current = false;
      }
    }
  }, [virtualRows, rows, infiniteScroll]);

  if (!table || !virtualizer || !rows || !virtualRows) return null;

  const showLoadingIndicator = infiniteScroll?.enabled && infiniteScroll.isLoading;

  return (
    <div
      className={styles[CSS.tbody]}
      role="rowgroup"
      style={{
        height: totalSize,
        position: 'relative',
        width: '100%',
      }}
    >
      {virtualRows.map((virtualRow) => {
        const row = rows[virtualRow.index];
        if (!row) return null;

        return <TableRow key={row.id} row={row} size={virtualRow.size} start={virtualRow.start} />;
      })}
      {showLoadingIndicator && (
        <div
          className={styles['griddy-loading-indicator']}
          style={{
            bottom: 0,
            left: 0,
            position: 'absolute',
            right: 0,
          }}
        >
          <div className={styles['griddy-loading-spinner']}>Loading more...</div>
        </div>
      )}
    </div>
  );
}
