/* global React, RC, Hls */
// Incoming-broadcast popup — Editorial. Triggered by WS event
// `broadcast_pending`. Mini-HLS preview + classification form.
//
// Reused as "edit broadcast" modal in the stream tab (when the admin
// passes a `broadcast` prop).

const { useState: useSI, useEffect: useEI, useRef: useRI } = React;

function IncomingBroadcastWatcher({ toast, onClassified, onRejected }) {
  const [queue, setQueue] = useSI([]);
  const current = queue[0] || null;

  useEI(() => {
    const conn = RC.openWs({
      token: RC.getToken(),
      handlers: {
        onMessage: (type, msg) => {
          if (type === 'broadcast_pending') {
            setQueue((q) => q.some((m) => m.broadcastId === msg.broadcastId) ? q : [...q, msg]);
          } else if (type === 'broadcast_ended') {
            setQueue((q) => q.filter((m) => m.broadcastId !== msg.broadcastId));
          }
        },
      },
    });
    // On boot, surface any already-pending broadcasts (page reload while pending)
    RC.apiFetch('/api/broadcasts?status=pending')
      .then((rows) => setQueue((q) => {
        const seen = new Set(q.map((m) => m.broadcastId));
        const more = rows.filter((r) => !seen.has(r.id)).map((r) => ({
          type: 'broadcast_pending',
          broadcastId: r.id, streamId: r.streamId,
          streamName: r.streamName, startedAt: r.startedAt,
          suggested: { name: r.name, location: r.location, visibility: 'public' },
        }));
        return [...q, ...more];
      }))
      .catch(() => {});
    return () => conn.close();
  }, []);

  if (!current) return null;
  return (
    <ClassifyBroadcastModal
      broadcastId={current.broadcastId}
      streamId={current.streamId}
      streamName={current.streamName}
      startedAt={current.startedAt}
      suggested={current.suggested}
      title="Incoming"
      onClose={async () => {
        if (!confirm('Stream ablehnen? Publisher wird gekickt.')) return;
        try {
          await RC.apiFetch(`/api/broadcasts/${current.broadcastId}/reject`, { method: 'POST' });
          toast?.('Broadcast abgelehnt');
        } catch (e) { toast?.(e.message, 'error'); }
        setQueue((q) => q.slice(1));
        onRejected?.();
      }}
      onSaved={async () => {
        toast?.('Broadcast freigegeben');
        setQueue((q) => q.slice(1));
        onClassified?.();
      }}
      toast={toast}
    />
  );
}

function ClassifyBroadcastModal({
  broadcastId, broadcast, streamName, streamId, startedAt,
  suggested, title = 'Incoming',
  onClose, onSaved, toast,
}) {
  const id = broadcastId || broadcast?.id;
  const initial = broadcast || {};

  const [name, setName] = useSI(initial.name || suggested?.name || '');
  const [location, setLocation] = useSI(initial.location || suggested?.location || '');
  const [visibility, setVisibility] = useSI(
    (initial.visibility && initial.visibility !== 'pending') ? initial.visibility :
    (suggested?.visibility && suggested.visibility !== 'pending') ? suggested.visibility :
    'public'
  );
  const [pw, setPw] = useSI(initial.viewerPassword || suggested?.viewerPassword || '');
  const [busy, setBusy] = useSI(false);

  const videoRef = useRI(null);
  const hlsRef = useRI(null);
  const [previewUrl, setPreviewUrl] = useSI(null);
  const [resolvedStreamName, setResolvedStreamName] = useSI(streamName || null);
  const [tick, setTick] = useSI(Date.now());

  useEI(() => {
    const t = setInterval(() => setTick(Date.now()), 1000);
    return () => clearInterval(t);
  }, []);

  useEI(() => {
    if (!id) return;
    RC.apiFetch('/api/broadcasts/' + id).then((b) => {
      if (b.playback?.hls) setPreviewUrl(b.playback.hls);
      if (!resolvedStreamName && b.streamName) setResolvedStreamName(b.streamName);
      if (!initial.id && !suggested) {
        if (!name && b.name) setName(b.name);
        if (!location && b.location) setLocation(b.location);
        if (b.visibility && b.visibility !== 'pending') setVisibility(b.visibility);
        if (b.viewerPassword) setPw(b.viewerPassword);
      }
    }).catch(() => {});
  }, [id]);

  useEI(() => {
    const v = videoRef.current; if (!v || !previewUrl) return;
    if (v.canPlayType('application/vnd.apple.mpegurl')) {
      v.src = previewUrl; v.play().catch(() => {});
      return;
    }
    if (window.Hls && Hls.isSupported()) {
      const h = new Hls({ lowLatencyMode: true, liveSyncDuration: 2 });
      h.loadSource(previewUrl); h.attachMedia(v);
      hlsRef.current = h; v.play().catch(() => {});
    }
    return () => { try { hlsRef.current?.destroy(); } catch (_) {} hlsRef.current = null; };
  }, [previewUrl]);

  const valid = name.trim().length > 0 && (visibility === 'public' || (visibility === 'private' && pw.length >= 4));
  const elapsed = startedAt ? Math.max(0, Math.floor((tick / 1000) - startedAt)) : null;

  const submit = async (e) => {
    e?.preventDefault?.();
    if (!valid || !id) return;
    setBusy(true);
    try {
      await RC.apiFetch(`/api/broadcasts/${id}/classify`, {
        method: 'POST',
        body: {
          name: name.trim(),
          location: location.trim() || null,
          visibility,
          ...(visibility === 'private' ? { viewerPassword: pw } : {}),
        },
      });
      await onSaved?.();
    } catch (err) { toast?.(err.message, 'error'); }
    finally { setBusy(false); }
  };

  return (
    <div className="ed-modal-backdrop">
      <form className="ed-modal ed-modal--wide" onSubmit={submit} onClick={(e) => e.stopPropagation()}>
        <div className="ed-modal__head">
          <div>
            <div className="ed-modal__lead">
              <span className="ed-live" style={{ fontSize: 11, marginRight: 12 }}>{title}</span>
              {resolvedStreamName && (
                <span style={{ color: 'var(--ed-cream-faint)' }}>
                  {resolvedStreamName}
                </span>
              )}
            </div>
            <h2 className="ed-modal__title">
              {broadcastId ? <>An <em>incoming</em> signal.</> : <>Edit <em>broadcast</em>.</>}
            </h2>
          </div>
          {elapsed != null && (
            <div style={{ textAlign: 'right' }}>
              <div className="ed-form-row__label">started</div>
              <div className="ed-mono" style={{ color: 'var(--ed-cream)', fontSize: 13 }}>
                {elapsed}s ago
              </div>
            </div>
          )}
        </div>

        <div className="ed-stage" style={{ aspectRatio: '16 / 9', marginBottom: 8 }}>
          <video ref={videoRef} muted playsInline autoPlay
                 style={{ width: '100%', height: '100%', objectFit: 'contain', background: '#000' }} />
          {!previewUrl && (
            <div style={{ position: 'absolute', inset: 0, display: 'flex', alignItems: 'center',
                          justifyContent: 'center', color: 'var(--ed-cream-faint)',
                          fontFamily: 'var(--ed-body)', fontStyle: 'italic', fontSize: 12 }}>
              warming the lens…
            </div>
          )}
        </div>

        <div className="ed-form-row--double">
          <FormField label="Name">
            <input className="ed-input" value={name} onChange={(e) => setName(e.target.value)}
                   placeholder="e.g. Hockenheim Trackday" required autoFocus />
          </FormField>
          <FormField label="Origin">
            <input className="ed-input" value={location} onChange={(e) => setLocation(e.target.value)}
                   placeholder="e.g. Hockenheim" />
          </FormField>
        </div>

        <FormField label="Visibility">
          <div className="ed-choice-grid" style={{ gridTemplateColumns: '1fr 1fr' }}>
            <button type="button" className="ed-choice"
                    aria-selected={visibility === 'public'}
                    onClick={() => setVisibility('public')}>
              <span className="ed-choice__title">Public</span>
              <span className="ed-choice__sub">anyone with the link</span>
            </button>
            <button type="button" className="ed-choice"
                    aria-selected={visibility === 'private'}
                    onClick={() => setVisibility('private')}>
              <span className="ed-choice__title">Private</span>
              <span className="ed-choice__sub">password-gated</span>
            </button>
          </div>
        </FormField>

        {visibility === 'private' && (
          <FormField label="Stream password">
            <div style={{ display: 'flex', gap: 8 }}>
              <input className="ed-input" value={pw} onChange={(e) => setPw(e.target.value)}
                     required minLength={4} placeholder="min 4 chars" />
              <button type="button" className="ed-btn ed-btn--ghost"
                      onClick={() => setPw(Math.random().toString(36).slice(2, 10))}>↻</button>
            </div>
          </FormField>
        )}

        <div className="ed-modal__foot" style={{ justifyContent: 'space-between' }}>
          <button type="button" className="ed-btn ed-btn--ghost"
                  onClick={onClose}
                  style={{ borderColor: 'var(--ed-rule)', color: 'var(--ed-cream-faint)' }}>
            ✕ reject signal
          </button>
          <button type="submit" className="ed-btn ed-btn--ferrari" disabled={busy || !valid}>
            {busy ? <span className="ed-spin" /> : 'broadcast ›'}
          </button>
        </div>
      </form>
    </div>
  );
}

function FormField({ label, children }) {
  return (
    <label className="ed-form-row">
      <span className="ed-form-row__label">{label}</span>
      {children}
    </label>
  );
}

window.IncomingBroadcastWatcher = IncomingBroadcastWatcher;
window.ClassifyBroadcastModal = ClassifyBroadcastModal;
