/* global React, RC */
// Clip editor — Editorial. Pick start/end on a recording, post the clip,
// poll until it's ready, expose the download link.

const { useState: useSCE, useEffect: useECE, useRef: useRefCE } = React;

function ClipEditor({ recording, onClose, toast }) {
  const videoRef = useRefCE(null);
  const [time, setTime] = useSCE(0);
  const [duration, setDuration] = useSCE(recording.durationSeconds || 0);
  const [start, setStart] = useSCE(0);
  const [end, setEnd] = useSCE(Math.min(15, recording.durationSeconds || 15));
  const [name, setName] = useSCE('');
  const [busy, setBusy] = useSCE(false);
  const [clip, setClip] = useSCE(null);

  useECE(() => {
    const v = videoRef.current; if (!v) return;
    const onLoaded = () => setDuration(v.duration || recording.durationSeconds || 0);
    const onTime = () => setTime(v.currentTime);
    v.addEventListener('loadedmetadata', onLoaded);
    v.addEventListener('timeupdate', onTime);
    return () => {
      v.removeEventListener('loadedmetadata', onLoaded);
      v.removeEventListener('timeupdate', onTime);
    };
  }, []);

  useECE(() => {
    if (!clip || clip.status === 'ready' || clip.status === 'failed') return;
    const t = setInterval(async () => {
      try {
        const c = await RC.apiFetch('/api/clips/' + clip.id);
        setClip(c);
        if (c.status === 'failed') toast?.('clip failed: ' + (c.error || ''), 'error');
      } catch (_) {}
    }, 1000);
    return () => clearInterval(t);
  }, [clip?.id, clip?.status]);

  const seek = (t) => {
    const v = videoRef.current; if (!v) return;
    v.currentTime = Math.max(0, Math.min(duration, t));
  };

  const submit = async () => {
    if (!(end > start)) { toast?.('end must be after start', 'error'); return; }
    setBusy(true);
    try {
      const c = await RC.apiFetch('/api/clips', {
        method: 'POST',
        body: {
          recordingId: recording.id,
          name: name || `clip_${Math.round(start)}-${Math.round(end)}`,
          startSeconds: Number(start),
          endSeconds: Number(end),
        },
      });
      setClip(c);
    } catch (e) { toast?.(e.message, 'error'); }
    finally { setBusy(false); }
  };

  const fileUrl = `${RC.baseUrl}/api/replays/${recording.id}/file?token=${RC.getToken()}`;

  return (
    <div className="ed-modal-backdrop" onClick={onClose}>
      <div className="ed-modal ed-modal--wide" onClick={(e) => e.stopPropagation()}>
        <div className="ed-modal__head">
          <div>
            <div className="ed-modal__lead">Cutting room</div>
            <h2 className="ed-modal__title">A new <em>clip</em>.</h2>
          </div>
          <button className="ed-modal__close" onClick={onClose}>✕</button>
        </div>

        <div className="ed-stage" style={{ marginBottom: 14 }}>
          <video ref={videoRef} src={recording.fileUrl || fileUrl} controls
                 style={{ width: '100%', maxHeight: 360, display: 'block', background: '#000' }} />
        </div>

        <div className="ed-form-row--double" style={{ gridTemplateColumns: '1fr 1fr 1.6fr' }}>
          <NumField label="Start (s)" value={start} max={duration}
            onChange={setStart}
            extra={<button className="ed-btn ed-btn--ghost" onClick={() => setStart(time)}>use playhead</button>} />
          <NumField label="End (s)" value={end} max={duration}
            onChange={setEnd}
            extra={<button className="ed-btn ed-btn--ghost" onClick={() => setEnd(time)}>use playhead</button>} />
          <FormField label="Name">
            <input className="ed-input" value={name} onChange={(e) => setName(e.target.value)}
                   placeholder="e.g. overtake at T7" />
          </FormField>
        </div>

        <RangeBar duration={duration} start={start} end={end} time={time}
          onSeek={seek}
          onChangeStart={(s) => setStart(Math.min(s, end - 0.1))}
          onChangeEnd={(s) => setEnd(Math.max(s, start + 0.1))} />

        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center',
                      marginTop: 14, padding: '14px 0',
                      borderTop: '1px solid var(--ed-rule)' }}>
          <div style={{ fontFamily: 'var(--ed-body)', fontSize: 12, color: 'var(--ed-cream-dim)' }}>
            <span style={{ fontStyle: 'italic', color: 'var(--ed-cream-faint)' }}>length</span>{' '}
            <span className="ed-mono" style={{ color: 'var(--ed-cream)' }}>{RC.fmtDuration(end - start)}</span>
            <span style={{ margin: '0 12px', color: 'var(--ed-cream-trace)' }}>·</span>
            <span style={{ fontStyle: 'italic', color: 'var(--ed-cream-faint)' }}>recording</span>{' '}
            <span className="ed-mono" style={{ color: 'var(--ed-cream)' }}>{RC.fmtDuration(duration)}</span>
          </div>
          <div style={{ display: 'flex', gap: 8 }}>
            <button className="ed-btn" onClick={onClose}>cancel</button>
            <button className="ed-btn ed-btn--ferrari" onClick={submit} disabled={busy || (clip && clip.status === 'pending')}>
              {busy || (clip && clip.status === 'pending') ? <span className="ed-spin" /> : 'cut clip ›'}
            </button>
          </div>
        </div>

        {clip && (
          <div style={{
            marginTop: 18, padding: '18px 22px',
            border: '1px solid var(--ed-rule-strong)',
            borderLeft: '3px solid ' + (clip.status === 'failed' ? 'var(--ed-ferrari)' : 'var(--ed-amber)'),
          }}>
            <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
              <div>
                <span className="ed-form-row__label">Status</span>{' '}
                <span className={'ed-pill ' + (clip.status === 'ready' ? 'ed-pill--ready' : 'ed-pill--pending')}
                      style={{ marginLeft: 8 }}>
                  {clip.status}
                </span>
              </div>
              {clip.status === 'ready' && (
                <a className="ed-btn ed-btn--ferrari"
                   href={`${RC.baseUrl}/api/clips/${clip.id}/file?token=${RC.getToken()}`}
                   target="_blank" rel="noreferrer" style={{ textDecoration: 'none' }}>↓ download</a>
              )}
            </div>
            {clip.error && <div style={{ marginTop: 10, color: 'var(--ed-ferrari)',
                                          fontFamily: 'var(--ed-mono)', fontSize: 12 }}>{clip.error}</div>}
          </div>
        )}
      </div>
    </div>
  );
}

function NumField({ label, value, onChange, max, extra }) {
  return (
    <label className="ed-form-row">
      <span className="ed-form-row__label">{label}</span>
      <input className="ed-input" type="number" step="0.1" min="0" max={max} value={value}
             onChange={(e) => onChange(Math.max(0, Math.min(max || 1e9, Number(e.target.value))))} />
      {extra && <div style={{ marginTop: 6 }}>{extra}</div>}
    </label>
  );
}

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

function RangeBar({ duration, start, end, time, onSeek, onChangeStart, onChangeEnd }) {
  const trackRef = useRefCE(null);
  const dragRef = useRefCE(null);

  const tx = (e) => {
    const r = trackRef.current.getBoundingClientRect();
    return Math.max(0, Math.min(1, (e.clientX - r.left) / r.width));
  };
  const onDown = (kind) => (e) => {
    dragRef.current = kind;
    const move = (ev) => {
      const p = tx(ev) * (duration || 1);
      if (kind === 'start') onChangeStart(p);
      else if (kind === 'end') onChangeEnd(p);
      else if (kind === 'seek') onSeek(p);
    };
    const up = () => {
      window.removeEventListener('mousemove', move);
      window.removeEventListener('mouseup', up);
      dragRef.current = null;
    };
    window.addEventListener('mousemove', move);
    window.addEventListener('mouseup', up);
    move(e);
  };

  if (!duration) return null;
  const pctStart = (start / duration) * 100;
  const pctEnd = (end / duration) * 100;
  const pctTime = (time / duration) * 100;
  return (
    <div ref={trackRef} onMouseDown={onDown('seek')} style={{
      position: 'relative', height: 38,
      background: 'rgba(237, 229, 207, 0.04)',
      border: '1px solid var(--ed-rule)',
      cursor: 'pointer', marginTop: 18,
    }}>
      <div style={{
        position: 'absolute', top: 0, bottom: 0,
        left: pctStart + '%', width: (pctEnd - pctStart) + '%',
        background: 'rgba(220, 31, 31, 0.18)',
        borderLeft: '1px solid var(--ed-ferrari)',
        borderRight: '1px solid var(--ed-ferrari)',
      }} />
      <div style={{ position: 'absolute', top: 0, bottom: 0, left: pctTime + '%',
                    width: 1, background: 'var(--ed-cream)' }} />
      <Handle pct={pctStart} onMouseDown={onDown('start')} />
      <Handle pct={pctEnd} onMouseDown={onDown('end')} />
    </div>
  );
}
function Handle({ pct, onMouseDown }) {
  return (
    <div onMouseDown={(e) => { e.stopPropagation(); onMouseDown(e); }} style={{
      position: 'absolute', top: -3, bottom: -3, left: `calc(${pct}% - 5px)`, width: 10,
      background: 'var(--ed-ferrari)', cursor: 'ew-resize',
      boxShadow: '0 0 0 1px var(--ed-paper)',
    }} />
  );
}

window.ClipEditor = ClipEditor;
