// Shared "track row" — the cover + play-button + title/meta + trailing
// slot pattern that nearly every list view in the panel renders:
//
//   • Profile → "Meine Tracks", "Zuletzt gehört", "Meine Likes"
//   • Playlists → playlist detail track list
//   • Stats → Verlauf list
//   • Artists → artist detail track list
//
// Before extracting this, the same ~60-line block was copy-pasted
// across five screens, each with slight visual drift. One place to
// fix means one place to fix.
//
// Composition over props — `meta` and `trailing` accept JSX so each
// callsite can put whatever it needs (status pill, vote tally,
// remove button, AdminMenu, etc.) without us needing to enumerate
// every possible variant up front.
//
// What this component does NOT cover:
//   • home.jsx library — uses a grid-table layout with sortable
//     headers, fundamentally different visual structure.
//   • queue.jsx SubmissionCard — full card with action bar at the
//     bottom + vote tally; has its own primitive.
//   • reports.jsx — similar to SubmissionCard.

// React.memo wraps the row at the bottom of the file. With the
// memo + `useAudioStatus()` switch, parent re-renders (sort changes,
// likes toggles, etc.) don't propagate down to 50 rows unless the
// row's own props actually changed, AND playback ticks no longer
// re-render the row at 4-10 Hz. Together this drops home/library
// render cost by roughly an order of magnitude on big catalogs.
function TrackRowImpl({
  track,
  // Optional index column on the left. When provided, replaces with
  // a volume-bars indicator while the row is the currently-playing
  // track (Spotify-style affordance for "this is what's playing").
  index = null,
  // Override the default meta line (artist · duration). Pass JSX —
  // common patterns: ArtistLink + timeAgo, or status text, etc.
  meta = null,
  // Slot for everything that sits after the title block — status
  // pills, vote tallies, AdminMenu, remove buttons, etc.
  trailing = null,
  // Render a bottom hairline border. The parent decides per-row so
  // the last row in the list can stay borderless.
  border = false,
  // Bump background tint when this row is the currently-playing one.
  // Default: derived from useAudio().currentId === track.id, but
  // callers can pass an explicit boolean if they need different
  // semantics (e.g. "highlight track that just got added").
  highlight,
  // Override the play action. Default is audio.play(track) — almost
  // every caller wants this, but e.g. a "delete this track" row
  // might want a no-op cover.
  onPlay,
}) {
  // Status-only subscription — we only care whether THIS row is
  // currently the loaded track and whether playback is running.
  // Using `useAudio()` here would re-render the row on every
  // timeupdate tick (4-10 fires/sec); `useAudioStatus()` filters
  // those out and only fires on play/pause/track-switch.
  const audio = useAudioStatus();
  const isCurrent = highlight ?? (audio.currentId === track.id);
  const isPlaying = isCurrent && audio.isPlaying;

  const handlePlay = onPlay || (() => audio.play(track));

  // Default meta line if none provided. Uses ArtistLink so admins
  // can jump to the artist page; non-admins see plain text. Adds
  // duration if available.
  const defaultMeta = (
    <>
      <ArtistLink identifier={track.identifier} name={track.artist} size={11.5}/>
      {track.duration ? <>{' · '}{fmt(track.duration)}</> : null}
    </>
  );

  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 12,
      padding: '10px 18px',
      borderBottom: border ? '1px solid var(--border-hairline)' : 'none',
      background: isCurrent ? 'rgba(169,114,244,0.08)' : 'transparent',
      transition: 'background 150ms var(--ease-out)',
    }}>
      {/* Index / position cell. Renders a number normally, swaps
          to a volume-bars icon while the row is actively playing. */}
      {index != null && (
        <div style={{
          width: 24, fontSize: 13,
          color: isCurrent ? 'var(--coral)' : 'var(--fg-4)',
          textAlign: 'center',
          fontWeight: isCurrent ? 700 : 500,
          fontVariantNumeric: 'tabular-nums',
          flexShrink: 0,
        }}>
          {isPlaying
            ? <ApIcon name="volume-high" size={13} color="var(--coral)"/>
            : index}
        </div>
      )}

      {/* Cover thumb — gradient or uploaded image. */}
      <Cover colors={track.cover} src={track.coverUrl} size={44} radius={10}/>

      {/* Play button — small circle next to the cover. Reuses the
          global audio service so play state is shared across every
          row in every list. */}
      {track.audioUrl !== null && (
        <button onClick={handlePlay}
          aria-label={isPlaying ? 'Pause' : 'Abspielen'}
          style={{
            width: 34, height: 34, borderRadius: '50%',
            background: isPlaying ? 'var(--grad-lila)' : 'rgba(196,154,255,0.10)',
            border: '1px solid var(--border-soft)',
            color: isPlaying ? 'var(--foam)' : 'var(--fg-2)',
            cursor: 'pointer', display: 'flex', alignItems: 'center', justifyContent: 'center',
            flexShrink: 0,
          }}>
          <ApIcon name={isPlaying ? 'pause' : 'play'} size={12}/>
        </button>
      )}

      {/* Title + meta. Min-width:0 lets text-ellipsis kick in when
          the title is longer than the available space. */}
      <div style={{ flex: 1, minWidth: 0 }}>
        <div style={{
          fontSize: 14, fontWeight: 700,
          color: isCurrent ? 'var(--coral)' : 'var(--foam)',
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
        }}>{track.title}</div>
        <div style={{
          fontSize: 11.5, color: 'var(--fg-3)',
          whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis',
          display: 'flex', alignItems: 'center', gap: 4,
        }}>
          {meta || defaultMeta}
        </div>
      </div>

      {/* Trailing slot. Holds whatever combination of pills / tally
          / menu / remove the parent wants. */}
      {trailing}
    </div>
  );
}

// Memoise the row so a parent re-render (sort change, search query
// typed, likes toggled, etc.) doesn't waste cycles on rows whose
// props are identical. Callers should pass STABLE references for
// `meta` / `trailing` / `onPlay` (i.e. useMemo / useCallback) to
// actually benefit from this — but even without that the audio-tick
// filter alone is a big win.
const TrackRow = React.memo(TrackRowImpl);
window.TrackRow = TrackRow;
