// Goyo Club — Left Index pane
// Per-character typewriter entry: each character span gets a global --char-i
// CSS variable; CSS animates pop-in by `var(--char-i) * char-stagger`.

// --- Static row -------------------------------------------------------------
function StaticRow({
  cells, hoverStyle,
  selected, hovered, onMouseEnter, onMouseLeave, onClick,
  index = 0, charOffset = 0, entering = true,
}) {
  const cls = [
    "row",
    entering ? "row--enter" : "",
    selected ? `row--selected row--selected-${hoverStyle}` : "",
    hovered && !selected ? `row--hover row--hover-${hoverStyle}` : "",
  ].filter(Boolean).join(" ");
  const style = { "--row-i": index };

  // Compute the starting char index for each cell within the row.
  let acc = charOffset;
  const cellStarts = cells.map((c) => {
    const start = acc;
    acc += (c || "").length;
    return start;
  });

  return (
    <div className={cls} style={style} onMouseEnter={onMouseEnter} onMouseLeave={onMouseLeave} onClick={onClick} role="button" tabIndex={0}>
      {cells.map((c, i) => (
        <div key={i} className="cell">
          <span className="cell-text">
            {[...(c || "")].map((ch, j) => (
              <span key={j} className="cell-char" style={{ "--char-i": cellStarts[i] + j }}>{ch}</span>
            ))}
          </span>
        </div>
      ))}
    </div>
  );
}

// --- Left Pane --------------------------------------------------------------
function LeftPane({
  rows,
  hoveredId, setHoveredId,
  selectedId, setSelectedId,
  hoverStyle,
  onReset,
  onLoadMore, hasMore,
}) {
  // Only the first INITIAL_BATCH_SIZE rows get the per-character typewriter
  // entry. Rows added later by LOAD MORE skip the animation entirely and
  // appear instantly — otherwise their global --char-i would push their
  // animation-delay multiple seconds past the click, leaving them invisible
  // while still hover-able. Should match PAGE_SIZE in app.jsx.
  const INITIAL_BATCH_SIZE = 30;

  // Accumulate global char index across rows so each row's chars get a unique
  // --char-i for ordered typewriter pop-in. We also track `firstBatchChars`
  // separately so the LOAD MORE / RESET ALL controls fade in after just the
  // initial batch's typewriter finishes (not the entire dataset).
  let charOffset = 0;
  let firstBatchChars = 0;

  return (
    <div className="left">
      <div className="index">
        <div className="index__scroll">
          {rows.map((r, i) => {
            const cells = [r.type, r.series || "", r.title, r.meta, r.date];
            const start = charOffset;
            charOffset += cells.reduce((s, c) => s + c.length, 0);
            if (i < INITIAL_BATCH_SIZE) firstBatchChars = charOffset;
            return (
              <StaticRow
                key={r.id}
                cells={cells}
                hoverStyle={hoverStyle}
                selected={selectedId === r.id}
                hovered={hoveredId === r.id}
                onMouseEnter={() => setHoveredId(r.id)}
                onMouseLeave={() => setHoveredId(null)}
                onClick={() => setSelectedId(r.id)}
                index={i}
                charOffset={start}
                entering={i < INITIAL_BATCH_SIZE}
              />
            );
          })}
          {rows.length === 0 && (
            <div className="index__empty"><span>NO RESULTS</span></div>
          )}
          <div className="index__controls" style={{ "--char-i": firstBatchChars }}>
            <button
              className="load-more"
              onClick={onLoadMore}
              disabled={!hasMore}
              title={hasMore ? "Load 30 more rows" : "End of list"}>
              [ <span className="btn-label">{hasMore ? "LOAD MORE" : "END"}</span> ]
            </button>
            <button
              className="reset-btn"
              onClick={onReset}
              title="Reset filters & selection">
              [ <span className="btn-label">RESET ALL</span> ]
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

window.GoyoLeft = { LeftPane };
