// Submit form — title, cover (image upload OR gradient palette), MP3.
// Server handles all validation + media processing + CDN upload.

function Field({ label, hint, children }) {
  return (
    <div style={{ marginBottom: 22 }}>
      <div style={{ fontSize: 12, fontWeight: 700, letterSpacing: 0.6, textTransform: 'uppercase', opacity: 0.7, marginBottom: 8 }}>{label}</div>
      {children}
      {hint && <div style={{ fontSize: 11.5, opacity: 0.5, marginTop: 6 }}>{hint}</div>}
    </div>
  );
}

function inputStyle(dark) {
  return {
    width: '100%', padding: '12px 14px', borderRadius: 12,
    background: dark ? 'rgba(255,255,255,0.04)' : 'rgba(255,255,255,0.7)',
    border: dark ? '1px solid rgba(255,255,255,0.1)' : '1px solid rgba(0,0,0,0.08)',
    color: 'inherit', fontSize: 14, fontFamily: 'inherit', outline: 'none',
  };
}

function SubmitScreen({ me, dark, setRoute, refresh }) {
  const [title, setTitle] = React.useState('');
  const [coverIdx, setCoverIdx] = React.useState(0);
  const [coverFile, setCoverFile] = React.useState(null);
  // Raw, pre-crop image — fed into the ImageCropper modal. After
  // cropping, the result lands in coverFile and gets uploaded.
  const [rawCoverFile, setRawCoverFile] = React.useState(null);
  const [mp3, setMp3] = React.useState(null);
  const [mp3Url, setMp3Url] = React.useState(null);
  const [mp3Drag, setMp3Drag] = React.useState(false);
  const [coverDrag, setCoverDrag] = React.useState(false);
  const [busy, setBusy] = React.useState(false);
  const [posted, setPosted] = React.useState(false);
  const [err, setErr] = React.useState('');

  // Manage object URL lifecycle for the audio preview — without revocation
  // these slowly leak memory across many file picks.
  React.useEffect(() => {
    if (!mp3) { setMp3Url(null); return; }
    const url = URL.createObjectURL(mp3);
    setMp3Url(url);
    return () => URL.revokeObjectURL(url);
  }, [mp3]);

  // Cover preview gets its own object URL — same lifecycle handling.
  const coverPreviewUrl = React.useMemo(
    () => coverFile ? URL.createObjectURL(coverFile) : null,
    [coverFile],
  );
  React.useEffect(() => {
    if (!coverPreviewUrl) return;
    return () => URL.revokeObjectURL(coverPreviewUrl);
  }, [coverPreviewUrl]);

  const palettes = [
    ['#ff4d8d', '#7c3aed'], ['#06b6d4', '#ec4899'], ['#f59e0b', '#ef4444'],
    ['#a855f7', '#3b82f6'], ['#10b981', '#06b6d4'], ['#fbbf24', '#f97316'],
    ['#6366f1', '#a855f7'], ['#f472b6', '#fb923c'], ['#34d399', '#0ea5e9'],
  ];

  if (isBanned(me)) {
    return (
      <div style={{ padding: '60px 32px', maxWidth: 600, margin: '0 auto' }}>
        <ApGlass dark={dark} radius={20} padding={36} style={{
          textAlign: 'center',
          border: '1px solid rgba(239,68,68,0.4)',
        }}>
          <div style={{
            width: 60, height: 60, borderRadius: '50%', margin: '0 auto 16px',
            background: 'rgba(239,68,68,0.18)', display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <ApIcon name="x" size={32} color="#f87171"/>
          </div>
          <h2 style={{ fontSize: 22, fontWeight: 800, margin: '0 0 8px' }}>Du bist gebannt</h2>
          <p style={{ fontSize: 14, opacity: 0.7, lineHeight: 1.55, margin: 0 }}>
            Solange dein Bann aktiv ist, kannst du keine Tracks hochladen.
            Wenn das ein Fehler ist, melde dich beim Team.
          </p>
        </ApGlass>
      </div>
    );
  }

  if (isBlocked(me)) {
    return (
      <div style={{ padding: '60px 32px', maxWidth: 600, margin: '0 auto' }}>
        <ApGlass dark={dark} radius={20} padding={36} style={{
          textAlign: 'center',
          border: '1px solid rgba(220,38,38,0.5)',
        }}>
          <div style={{
            width: 60, height: 60, borderRadius: '50%', margin: '0 auto 16px',
            background: 'rgba(127,29,29,0.25)', display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <ApIcon name="shield" size={32} color="#fca5a5"/>
          </div>
          <h2 style={{ fontSize: 22, fontWeight: 800, margin: '0 0 8px' }}>Vom Hochladen gesperrt</h2>
          <p style={{ fontSize: 14, opacity: 0.7, lineHeight: 1.55, margin: 0 }}>
            Ein Admin hat dich vom Hochladen gesperrt. Auf dem Server selbst bist du nicht eingeschränkt —
            nur neue Tracks gehen aktuell nicht. Melde dich beim Team, falls das ein Fehler ist.
          </p>
        </ApGlass>
      </div>
    );
  }

  if (!canSubmit(me)) {
    return (
      <div style={{ padding: '60px 32px', maxWidth: 600, margin: '0 auto' }}>
        <ApGlass dark={dark} radius={20} padding={36} style={{ textAlign: 'center' }}>
          <ApIcon name="clock" size={36} color="#fbbf24"/>
          <h2 style={{ fontSize: 22, fontWeight: 800, margin: '14px 0 8px' }}>Noch nicht ganz so weit</h2>
          <p style={{ fontSize: 14, opacity: 0.65, lineHeight: 1.55, margin: 0 }}>
            Du hast aktuell <b>{me.playtime}h</b> auf dem Server. Ab <b>100 Stunden</b> kannst du eigene Tracks hochladen.
          </p>
        </ApGlass>
      </div>
    );
  }

  // Eligible to submit but hasn't picked a stage name yet — route through
  // onboarding before the actual upload form. `onSaved={refresh}` is what
  // unblocks the user: it re-fetches /api/me, ApprovalApp updates its `me`
  // state, this screen re-renders, and `hasArtistProfile(me)` flips true.
  if (!hasArtistProfile(me)) {
    return <ArtistProfileForm me={me} dark={dark} mode="onboarding" onSaved={refresh}/>;
  }

  if (posted) {
    return (
      <div style={{ padding: '60px 32px', maxWidth: 600, margin: '0 auto' }}>
        <ApGlass dark={dark} radius={20} padding={36} style={{ textAlign: 'center' }}>
          <div style={{
            width: 60, height: 60, borderRadius: '50%', margin: '0 auto 16px',
            background: 'rgba(52,211,153,0.18)', display: 'flex', alignItems: 'center', justifyContent: 'center',
          }}>
            <ApIcon name="check" size={32} color="#34d399"/>
          </div>
          <h2 style={{ fontSize: 22, fontWeight: 800, margin: '0 0 8px' }}>Track ist hochgeladen</h2>
          <p style={{ fontSize: 14, opacity: 0.65, lineHeight: 1.55, margin: '0 0 22px' }}>
            Dein Track liegt jetzt zur Prüfung. Sobald entschieden wurde, siehst du das in deinem Profil.
          </p>
          <button onClick={() => setRoute('me')} style={{
            padding: '10px 20px', borderRadius: 10, background: '#ff4d8d', border: 'none',
            color: '#fff', fontSize: 13, fontWeight: 700, cursor: 'pointer',
          }}>Fertig</button>
        </ApGlass>
      </div>
    );
  }

  const handleSubmit = async (e) => {
    e.preventDefault();
    if (!title.trim() || !mp3) return;
    setBusy(true); setErr('');
    try {
      const form = new FormData();
      form.append('title', title.trim());
      form.append('coverGradient', JSON.stringify(palettes[coverIdx]));
      if (coverFile) form.append('cover', coverFile);
      form.append('mp3', mp3);
      await Api.submit(form);
      await refresh();
      setPosted(true);
      toast.success('Track hochgeladen — viel Erfolg!');
    } catch (ex) {
      const msg = ex.message || 'Hochladen fehlgeschlagen.';
      setErr(msg);
      toast.error(msg);
    } finally {
      setBusy(false);
    }
  };

  // Drop handlers reused for both file slots — set the right slot based on
  // MIME type. Reject anything that isn't audio/mpeg or an image.
  const handleMp3Drop = (e) => {
    e.preventDefault();
    setMp3Drag(false);
    const f = e.dataTransfer.files?.[0];
    if (!f) return;
    if (!/^audio\/(mpeg|mp3)$/i.test(f.type) && !f.name.toLowerCase().endsWith('.mp3')) {
      toast.error('Bitte eine MP3-Datei wählen.');
      return;
    }
    setMp3(f);
  };
  const handleCoverDrop = (e) => {
    e.preventDefault();
    setCoverDrag(false);
    const f = e.dataTransfer.files?.[0];
    if (!f) return;
    if (!/^image\//i.test(f.type)) {
      toast.error('Bitte ein Bild wählen.');
      return;
    }
    // Drop too goes through the cropper, same as file-picker. Even if
    // the user drops a square the modal lets them confirm + re-frame.
    setRawCoverFile(f);
  };

  return (
    <div style={{ padding: '28px 32px', maxWidth: 720, margin: '0 auto' }}>
      <h1 style={{ fontSize: 32, fontWeight: 800, letterSpacing: -0.7, margin: '0 0 6px' }}>Track hochladen</h1>
      <p style={{ fontSize: 14, opacity: 0.6, margin: '0 0 24px' }}>
        Lade deinen Track hoch und gib ihm einen Titel — der Rest läuft automatisch. Sobald er freigegeben ist, taucht er ingame auf.
      </p>

      <form onSubmit={handleSubmit}>
        <ApGlass dark={dark} radius={20} padding={24} style={{ marginBottom: 16 }}>
          <Field label="Titel">
            <input
              value={title} onChange={e => setTitle(e.target.value)}
              placeholder="Cinder Bloom"
              maxLength={80}
              style={inputStyle(dark)}
            />
          </Field>

          <Field label="Cover" hint="Eigenes Bild hochladen (wird auf 512×512 WebP komprimiert) — oder einen Farbverlauf als Platzhalter wählen.">
            <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
              {palettes.map((p, i) => (
                <button key={i} type="button" onClick={() => { setCoverIdx(i); setCoverFile(null); }} style={{
                  width: 64, height: 64, borderRadius: 12, padding: 0, cursor: 'pointer',
                  background: `linear-gradient(135deg, ${p[0]}, ${p[1]})`,
                  border: !coverFile && i === coverIdx ? '3px solid #ff4d8d' : '3px solid transparent',
                  boxShadow: !coverFile && i === coverIdx ? '0 6px 18px rgba(255,77,141,0.4)' : 'none',
                  transition: 'all 0.15s',
                }}/>
              ))}
              <label
                onDragOver={(e) => { e.preventDefault(); setCoverDrag(true); }}
                onDragLeave={() => setCoverDrag(false)}
                onDrop={handleCoverDrop}
                style={{
                  width: 64, height: 64, borderRadius: 12, cursor: 'pointer',
                  background: coverPreviewUrl
                    ? `url(${coverPreviewUrl}) center/cover`
                    : (dark ? 'rgba(255,255,255,0.05)' : 'rgba(0,0,0,0.04)'),
                  border: coverFile
                    ? '3px solid #ff4d8d'
                    : coverDrag
                      ? '3px dashed #ff4d8d'
                      : (dark ? '2px dashed rgba(255,255,255,0.2)' : '2px dashed rgba(0,0,0,0.15)'),
                  color: 'inherit', display: 'flex', alignItems: 'center', justifyContent: 'center',
                  opacity: coverFile ? 1 : 0.6, transition: 'border 0.15s',
                }}
              >
                {!coverFile && <ApIcon name="image" size={22}/>}
                <input type="file" accept="image/*" hidden onChange={e => {
                  const f = e.target.files?.[0];
                  if (f) setRawCoverFile(f);
                  e.target.value = '';
                }}/>
              </label>
            </div>
          </Field>

          <Field label="Audio-Datei" hint="MP3, bis zu 22 MB. Wird automatisch auf 96 kbps gebracht, damit alle Tracks gleich klingen.">
            <label
              onDragOver={(e) => { e.preventDefault(); setMp3Drag(true); }}
              onDragLeave={() => setMp3Drag(false)}
              onDrop={handleMp3Drop}
              style={{
                display: 'flex', alignItems: 'center', gap: 14, padding: 16, borderRadius: 14,
                background: mp3Drag
                  ? 'rgba(255,77,141,0.10)'
                  : (dark ? 'rgba(255,255,255,0.04)' : 'rgba(0,0,0,0.03)'),
                border: mp3Drag
                  ? '2px dashed #ff4d8d'
                  : mp3
                    ? '1px dashed rgba(52,211,153,0.5)'
                    : (dark ? '1px dashed rgba(255,255,255,0.2)' : '1px dashed rgba(0,0,0,0.15)'),
                cursor: 'pointer', transition: 'all 0.15s',
              }}
            >
              <div style={{
                width: 44, height: 44, borderRadius: 10, flexShrink: 0,
                background: mp3 ? 'rgba(52,211,153,0.18)' : (dark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.05)'),
                display: 'flex', alignItems: 'center', justifyContent: 'center',
              }}>
                <ApIcon name={mp3 ? 'music' : 'upload'} size={20} color={mp3 ? '#34d399' : 'currentColor'}/>
              </div>
              <div style={{ flex: 1, minWidth: 0 }}>
                <div style={{ fontSize: 13.5, fontWeight: 600, whiteSpace: 'nowrap', overflow: 'hidden', textOverflow: 'ellipsis' }}>
                  {mp3?.name || (mp3Drag ? 'Datei hier loslassen' : 'MP3 auswählen')}
                </div>
                <div style={{ fontSize: 11.5, opacity: 0.55, marginTop: 2 }}>
                  {mp3 ? `${(mp3.size / 1048576).toFixed(1)} MB · bereit zum Hochladen` : 'oder einfach hierher ziehen'}
                </div>
              </div>
              {mp3 && (
                <button
                  type="button"
                  onClick={(e) => { e.preventDefault(); setMp3(null); }}
                  title="Entfernen"
                  style={{
                    background: 'none', border: 'none', cursor: 'pointer',
                    color: 'inherit', opacity: 0.5, padding: 6, display: 'flex',
                  }}
                >
                  <ApIcon name="x" size={16}/>
                </button>
              )}
              <input
                type="file" accept=".mp3,audio/mpeg" hidden
                onChange={e => setMp3(e.target.files?.[0] || null)}
              />
            </label>

            {mp3Url && (
              <audio
                src={mp3Url}
                controls
                style={{
                  width: '100%', marginTop: 12,
                  filter: dark ? 'invert(0.85)' : 'none',
                  borderRadius: 12,
                }}
              />
            )}
          </Field>
        </ApGlass>

        {err && <div style={{ color: '#f87171', fontSize: 13, padding: '0 4px 12px' }}>{err}</div>}

        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <ApGlass dark={dark} radius={12} padding={'10px 14px'} style={{ display: 'flex', alignItems: 'center', gap: 10, fontSize: 12.5 }}>
            <ApIcon name="help" size={16} color="#a78bfa"/>
            <div style={{ opacity: 0.75 }}>
              Hochgeladen als <b><ApPlayerName player={me} size={12.5} opacity={1}/></b> · {me.playtime}h Spielzeit
            </div>
          </ApGlass>
          <div style={{ flex: 1 }}/>
          <button type="submit" disabled={!title.trim() || !mp3 || busy} style={{
            padding: '12px 22px', borderRadius: 12, border: 'none', cursor: 'pointer',
            background: title.trim() && mp3 && !busy ? 'linear-gradient(135deg, #ff4d8d, #7c3aed)' : (dark ? 'rgba(255,255,255,0.08)' : 'rgba(0,0,0,0.08)'),
            color: '#fff', fontSize: 14, fontWeight: 700,
            opacity: title.trim() && mp3 && !busy ? 1 : 0.5,
            boxShadow: title.trim() && mp3 && !busy ? '0 8px 24px rgba(255,77,141,0.35)' : 'none',
          }}>
            {busy ? 'Wird hochgeladen…' : 'Track hochladen'}
          </button>
        </div>
      </form>

      {rawCoverFile && (
        <ImageCropper
          file={rawCoverFile}
          dark={dark}
          onCancel={() => setRawCoverFile(null)}
          onCrop={(cropped) => {
            setCoverFile(cropped);
            setRawCoverFile(null);
          }}
        />
      )}
    </div>
  );
}

window.SubmitScreen = SubmitScreen;
