import { useEffect, useMemo, useRef } from 'react';
import { Loader2, Music4 } from 'lucide-react';
import type { LyricLine } from './lyrics';
import { seekPlayer } from './player-time';
import { useActiveLyricIndex } from './useLyrics';

type LyricsPaneProps = {
  lines: LyricLine[] | null;
  synced: boolean;
  loading: boolean;
};

/**
 * The lyrics sheet. Synced (.lrc) lyrics centre, highlight the current line, auto-scroll and seek on
 * click; plain (.txt) lyrics left-align and scroll by hand only.
 *
 * It takes no position prop: it subscribes to the player clock itself and only re-renders when the
 * highlight moves, so the sixty-frames-a-second feed never reaches the DOM.
 */
export const LyricsPane = ({ lines, synced, loading }: LyricsPaneProps) => {
  const scrollRef = useRef<HTMLDivElement>(null);
  const lineRefs = useRef<(HTMLParagraphElement | null)[]>([]);
  const activeIndex = useActiveLyricIndex(lines, synced);

  // Keep the active line ~40% down the panel. scrollTop rather than scrollIntoView, which would also
  // scroll every ancestor and drag the whole workspace.
  useEffect(() => {
    if (!synced || activeIndex < 0) return;
    const box = scrollRef.current;
    const el = lineRefs.current[activeIndex];
    if (!box || !el) return;
    box.scrollTo({ top: Math.max(0, el.offsetTop - box.clientHeight * 0.4), behavior: 'smooth' });
  }, [activeIndex, synced]);

  const rendered = useMemo(() => {
    if (!lines) return null;
    return lines.map((line, i) => {
      const active = synced && i === activeIndex;
      const seekable = synced && line.timeSec != null;
      return (
        <p
          key={i}
          ref={(el) => {
            lineRefs.current[i] = el;
          }}
          onClick={seekable ? () => seekPlayer(line.timeSec!) : undefined}
          className={[
            'py-1 text-[15px] font-semibold leading-7 transition-colors duration-200',
            synced ? 'text-center' : 'text-left text-foreground/85',
            // Only the colour changes on the active line — no weight or size change, so nothing reflows
            // and the sheet does not jitter as the highlight moves.
            active ? 'text-foreground' : synced ? 'text-muted-foreground' : '',
            seekable ? 'cursor-pointer hover:text-foreground/80' : '',
          ]
            .filter(Boolean)
            .join(' ')}
        >
          {line.text || (synced ? '♪' : ' ')}
        </p>
      );
    });
  }, [lines, synced, activeIndex]);

  const empty = !loading && (!lines || !lines.length);

  return (
    <div ref={scrollRef} className="h-full overflow-y-auto px-6 pt-3">
      {loading && (
        <div className="flex h-full items-center justify-center text-muted-foreground">
          <Loader2 size={20} className="animate-spin" />
        </div>
      )}
      {empty && (
        <div className="flex h-full flex-col items-center justify-center gap-2 text-muted-foreground">
          <Music4 size={28} className="opacity-40" />
          <p className="text-sm">No lyrics for this track.</p>
        </div>
      )}
      {!loading && <div className="mx-auto max-w-2xl">{rendered}</div>}
      {/* Tail so the last lines can still scroll up to the 40% mark. */}
      {!loading && synced && <div style={{ height: '55%' }} />}
    </div>
  );
};
