// File-search results list. Controlled component — page state lives in App.
// Server handles filtering and pagination; props are the source of truth.

const TYPE_HAS_LABEL = new Set(['RULE', 'SET', 'GROUP'])

function ResultsList({ results, query, onOpen, loading, page, totalPages, totalCount, onPageChange, fileType, sortBy, sortDir, onSortChange }) {
  const showType      = TYPE_HAS_LABEL.has(fileType)
  const showOrderType = fileType === 'GROUP'

  function SortHeader({ col, children }) {
    const active = sortBy === col
    const arrow = active ? (sortDir === 'asc' ? ' ↑' : ' ↓') : ''
    return (
      <button className={cx("pv-col-sort-btn", active && "is-active")} onClick={() => onSortChange(col)}>
        {children}{arrow && <span className="pv-col-sort-arrow">{arrow}</span>}
      </button>
    )
  }

  if (loading) {
    return (
      <div className="pv-loading" data-screen-label="Results loading">
        <div className="pv-spinner" />
        <span>Searching activity + common repos…</span>
      </div>
    );
  }

  if (!results || results.length === 0) {
    return (
      <div className="pv-empty" data-screen-label="Results empty">
        <div>No files matched <code style={{ background: "var(--slate-100)", padding: "1px 6px", borderRadius: 4 }}>{query || "—"}</code>.</div>
        <div className="hint">Try a partial ID (e.g. PLRL), a keyword from the name, or change Type.</div>
      </div>
    );
  }

  const safePage       = page || 1
  const safeTotalPages = totalPages || 1
  const safeTotalCount = totalCount || results.length

  return (
    <div className="pv-results" data-screen-label="Results list">
      <div className={cx("pv-results-col-head", showType && "has-type", showOrderType && "has-order")}>
        <span className="pv-col-id"><SortHeader col="id">ID</SortHeader></span>
        <span className="pv-col-name"><SortHeader col="name">Name</SortHeader></span>
        {showType && <span className="pv-col-type"><SortHeader col="type">Type</SortHeader></span>}
        {showOrderType && <span className="pv-col-order">Order Type</span>}
        <span className="pv-col-repo">Repo</span>
      </div>

      <ul className="pv-result-rows">
        {results.map((r) => (
          <li key={r.id} className={cx("pv-result-row", showType && "has-type", showOrderType && "has-order")} onClick={() => onOpen(r)} tabIndex="0"
              onKeyDown={(e) => (e.key === "Enter" || e.key === " ") && (e.preventDefault(), onOpen(r))}>
            <div className="pv-result-id-col">{highlightText(r.id, query)}</div>
            <div className="pv-result-name-col">
              {r.name && r.name !== r.id ? highlightText(r.name, query) : '—'}
            </div>
            {showType && (
              <div className="pv-result-type-col">
                {r.typeValue
                  ? <span className="pv-type-label">{r.typeValue}</span>
                  : <span className="pv-type-label is-empty">—</span>}
              </div>
            )}
            {showOrderType && (
              <div className="pv-result-type-col">
                {r.orderType
                  ? <span className="pv-type-label">{r.orderType}</span>
                  : <span className="pv-type-label is-empty">—</span>}
              </div>
            )}
            <div className="pv-result-meta">
              <span className={cx("pv-repo-pill", r.repo === "common" && "is-common")}>{r.repo}</span>
              <Icon name="chevron-down" size={16} />
            </div>
          </li>
        ))}
      </ul>

      {safeTotalPages > 1 && (
        <div className="pv-pagination">
          <Button variant="secondary" size="sm" disabled={safePage <= 1} onClick={() => onPageChange(safePage - 1)}>‹ Prev</Button>
          <span className="pv-pagination-pages">
            {pageWindows(safePage, safeTotalPages).map((item, i) =>
              item === '…'
                ? <span key={`e${i}`} className="pv-pagination-ellipsis">…</span>
                : <button key={item}
                    className={cx("pv-pagination-num", item === safePage && "is-active")}
                    onClick={() => onPageChange(item)}>{item}</button>
            )}
          </span>
          <Button variant="secondary" size="sm" disabled={safePage >= safeTotalPages} onClick={() => onPageChange(safePage + 1)}>Next ›</Button>
        </div>
      )}
    </div>
  );
}

// Returns array of 1-based page numbers + '…' sentinels.
// Always shows first, last, and a ±2 window around current page.
function pageWindows(current, total) {
  if (total <= 7) return Array.from({ length: total }, (_, i) => i + 1)
  const WINDOW = 2
  const pages = new Set([1, total])
  for (let i = Math.max(1, current - WINDOW); i <= Math.min(total, current + WINDOW); i++) pages.add(i)
  const sorted = [...pages].sort((a, b) => a - b)
  const result = []
  let prev = 0
  for (const p of sorted) {
    if (p - prev > 1) result.push('…')
    result.push(p)
    prev = p
  }
  return result
}

function highlightText(text, q) {
  if (!q || q.length < 2) return text;
  const lc = text.toLowerCase();
  const lq = q.toLowerCase();
  const out = [];
  let i = 0, idx;
  while ((idx = lc.indexOf(lq, i)) >= 0) {
    if (idx > i) out.push(text.slice(i, idx));
    out.push(<mark key={idx} className="pv-hl">{text.slice(idx, idx + q.length)}</mark>);
    i = idx + q.length;
  }
  if (i < text.length) out.push(text.slice(i));
  return out.length ? out : text;
}

function shortPath(path) {
  if (!path) return '';
  const parts = path.split('/');
  const file = parts.pop();
  const dir = parts.slice(-2).join('/');
  return dir || file;
}

function formatBytes(n) {
  if (!n) return '';
  if (n < 1024) return `${n} B`;
  return `${(n / 1024).toFixed(1)} KB`;
}

Object.assign(window, { ResultsList });
