// Review queue — pending submissions oldest first. Audio playback is owned by
// the global AudioService so the same playback continues across tabs and one
// volume slider here controls everything.

function ReviewQueue({ submissions, me, refresh, dark }) {
  const audio = useAudio();
  const [expandedId, setExpandedId] = React.useState(null);
  const [query, setQuery] = React.useState('');

  const onPlay = (id) => {
    const sub = submissions.find(s => s.id === id);
    if (!sub?.audioUrl) return;
    audio.play(id, sub.audioUrl);
  };

  const onSeek = (id, seconds) => {
    if (audio.currentId !== id) return;
    audio.seek(seconds);
  };

  // Stop the global player if the track being acted on is the one we're
  // currently auditioning. Without this, accept/reject/block makes the
  // card disappear from the queue while the audio keeps playing in the
  // background — but the user has lost the play/pause surface to control
  // it.
  const stopIfActive = (id) => {
    if (audio.currentId === id) AudioService.stop();
  };

  const onVote = async (id, vote) => {
    try {
      const updated = await Api.vote(id, vote);
      // Auto-accept might have flipped the status server-side; if the
      // returned row is no longer pending and we were auditioning it,
      // kill the audio before the card unmounts.
      if (updated && updated.status && updated.status !== 'pending') {
        stopIfActive(id);
      }
      await refresh();
      toast.success(vote === 'accept' ? 'Stimme abgegeben: dafür' : 'Stimme abgegeben: dagegen');
    } catch (e) {
      toast.error('Abstimmen fehlgeschlagen: ' + e.message);
    }
  };
  const onForceAccept = async (id) => {
    if (!confirm('Diesen Track direkt veröffentlichen?')) return;
    try {
      stopIfActive(id);
      await Api.forceAccept(id);
      await refresh();
      toast.success('Track veröffentlicht.');
    } catch (e) {
      toast.error('Veröffentlichen fehlgeschlagen: ' + e.message);
    }
  };
  const onForceReject = async (id) => {
    if (!confirm('Diesen Track ablehnen? Die hochgeladenen Dateien werden vom CDN gelöscht.')) return;
    try {
      stopIfActive(id);
      await Api.forceReject(id);
      await refresh();
      toast.info('Track abgelehnt und vom CDN entfernt.');
    } catch (e) {
      toast.error('Ablehnen fehlgeschlagen: ' + e.message);
    }
  };
  const onBlockUser = async (id) => {
    const reason = prompt(
      'Creator dauerhaft sperren?\n\n' +
      'Der Track wird abgelehnt + vom CDN gelöscht, und der Spieler kann nichts mehr hochladen, ' +
      'bis du ihn unter „Sperren" wieder freigibst.\n\n' +
      'Optionaler Grund:'
    );
    if (reason === null) return;  // cancel
    try {
      stopIfActive(id);
      await Api.blockUser(id, reason);
      await refresh();
      toast.info('Creator gesperrt und Track abgelehnt.');
    } catch (e) {
      toast.error('Sperren fehlgeschlagen: ' + e.message);
    }
  };

  const pending = submissions
    .filter(s => s.status === 'pending')
    .sort((a, b) => a.submittedAt - b.submittedAt);

  const filtered = query.trim()
    ? pending.filter(s => {
        const q = query.toLowerCase();
        return s.title.toLowerCase().includes(q) || s.artist.toLowerCase().includes(q);
      })
    : pending;

  return (
    <div style={{ padding: '28px 32px', maxWidth: 1100, margin: '0 auto' }}>
      <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', gap: 24, marginBottom: 18, flexWrap: 'wrap' }}>
        <div style={{ flex: '1 1 420px' }}>
          <div style={{ fontSize: 12, opacity: 0.55, letterSpacing: 1.4, textTransform: 'uppercase', fontWeight: 700, marginBottom: 4 }}>
            {pending.length} in Prüfung · älteste zuerst
          </div>
          <h1 style={{ fontSize: 32, fontWeight: 800, letterSpacing: -0.7, margin: 0 }}>Zu prüfen</h1>
          <p style={{ fontSize: 14, opacity: 0.6, marginTop: 6, maxWidth: 620 }}>
            Ein Track wird automatisch veröffentlicht, sobald er <b>{Math.round(ACCEPT_THRESHOLD*100)}%</b> Zustimmung bei mindestens <b>{REQUIRED_VOTES}</b> Stimmen erreicht.
            {canForceAccept(me) && ' Admins können direkt veröffentlichen.'}
          </p>
        </div>
        <VolumeControl volume={audio.volume} setVolume={audio.setVolume} dark={dark}/>
      </div>

      {pending.length > 0 && (
        <SearchBar value={query} onChange={setQuery} dark={dark}/>
      )}

      {pending.length === 0 ? (
        <ApGlass dark={dark} radius={20} padding={48} style={{ textAlign: 'center' }}>
          <ApIcon name="check" size={36} color="#34d399"/>
          <div style={{ fontSize: 16, fontWeight: 700, marginTop: 10 }}>Nichts zu prüfen</div>
          <div style={{ fontSize: 13, opacity: 0.6, marginTop: 4 }}>Aktuell stehen keine Tracks zur Prüfung.</div>
        </ApGlass>
      ) : filtered.length === 0 ? (
        <ApGlass dark={dark} radius={20} padding={36} style={{ textAlign: 'center', opacity: 0.7 }}>
          <div style={{ fontSize: 14 }}>Keine Treffer für „{query}".</div>
        </ApGlass>
      ) : (
        filtered.map(sub => (
          <SubmissionCard
            key={sub.id}
            sub={sub} me={me} dark={dark}
            isPlaying={audio.currentId === sub.id}
            audioPos={audio.currentId === sub.id ? audio.pos : 0}
            expanded={expandedId === sub.id}
            onToggle={() => setExpandedId(id => id === sub.id ? null : sub.id)}
            onPlay={onPlay}
            onSeek={onSeek}
            onVote={onVote}
            onForceAccept={onForceAccept}
            onForceReject={onForceReject}
            onBlockUser={onBlockUser}
            refresh={refresh}
          />
        ))
      )}
    </div>
  );
}

// Pill-shaped search input that appears above the queue when there's
// something to search through. Filters by title and artist case-insensitively.
function SearchBar({ value, onChange, dark }) {
  return (
    <ApGlass dark={dark} radius={100} padding="8px 16px"
      style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 16 }}>
      <ApIcon name="search" size={16} color={dark ? 'rgba(255,255,255,0.5)' : 'rgba(0,0,0,0.5)'}/>
      <input
        value={value}
        onChange={e => onChange(e.target.value)}
        placeholder="Nach Titel oder Künstler suchen…"
        style={{
          flex: 1, background: 'transparent', border: 'none', outline: 'none',
          color: 'inherit', fontSize: 13.5,
        }}
      />
      {value && (
        <button onClick={() => onChange('')} style={{
          background: 'none', border: 'none', cursor: 'pointer',
          color: 'inherit', opacity: 0.5, padding: 4, display: 'flex',
        }}>
          <ApIcon name="x" size={14}/>
        </button>
      )}
    </ApGlass>
  );
}

// Compact glass card with a slider. Right of the queue header so users always
// have a volume knob within reach. Mute toggle remembers the previous level.
function VolumeControl({ volume, setVolume, dark }) {
  const muted = volume === 0;
  const lastRef = React.useRef(volume || 0.8);
  React.useEffect(() => { if (volume > 0) lastRef.current = volume; }, [volume]);

  const iconName = muted ? 'volume-mute' : volume < 0.5 ? 'volume-low' : 'volume-high';

  return (
    <ApGlass dark={dark} radius={100} padding={'8px 14px'} style={{
      display: 'flex', alignItems: 'center', gap: 10, minWidth: 200, flexShrink: 0,
    }}>
      <button
        onClick={() => setVolume(muted ? lastRef.current : 0)}
        title={muted ? 'Stumm aufheben' : 'Stumm'}
        style={{
          background: 'none', border: 'none', cursor: 'pointer', padding: 0,
          color: muted ? '#f87171' : '#ff4d8d', display: 'flex',
        }}
      >
        <ApIcon name={iconName} size={18} color="currentColor"/>
      </button>
      <input
        type="range"
        min={0} max={1} step={0.01}
        value={volume}
        onChange={(e) => setVolume(parseFloat(e.target.value))}
        style={{ flex: 1, cursor: 'pointer' }}
      />
      <div style={{ fontSize: 11, fontWeight: 700, opacity: 0.6, fontVariantNumeric: 'tabular-nums', minWidth: 28, textAlign: 'right' }}>
        {Math.round(volume * 100)}
      </div>
    </ApGlass>
  );
}

window.ReviewQueue = ReviewQueue;
