// JournalAdmin.jsx — admin CRUD for editorial / journal posts.
//
// Mounted from Admin.jsx via the new "Journal" tab. Talks to:
//   GET    /api/admin/journal          → list ALL articles (incl. drafts)
//   POST   /api/admin/journal          → create (multipart: hero + fields)
//   PATCH  /api/admin/journal/:id      → update (same multipart)
//   DELETE /api/admin/journal/:id      → remove
//
// On any mutation we call refreshArticles() (from Journal.jsx) so the
// public journal page + home teasers + phone listings update without
// a page reload.

const { useState: useStateJA, useEffect: useEffectJA, useRef: useRefJA } = React;

function JournalAdmin({ token, onUnauthorized }) {
  const [articles, setArticles]   = useStateJA([]);
  const [loading, setLoading]     = useStateJA(true);
  const [error, setError]         = useStateJA(null);
  const [editing, setEditing]     = useStateJA(null);    // article object or { __new: true }
  const [deletingId, setDeleting] = useStateJA(null);

  async function api(path, opts = {}) {
    const r = await fetch(path, {
      ...opts,
      headers: {
        ...(opts.headers || {}),
        Authorization: `Bearer ${token}`,
      },
    });
    if (r.status === 401) { onUnauthorized?.(); throw new Error('Session expired — please log in again.'); }
    const isJson = (r.headers.get('content-type') || '').includes('application/json');
    const d = isJson ? await r.json() : {};
    if (!r.ok) throw new Error(d.error || `HTTP ${r.status}`);
    return d;
  }

  async function refresh() {
    setLoading(true);
    setError(null);
    try {
      const d = await api('/api/admin/journal');
      setArticles(Array.isArray(d.articles) ? d.articles : []);
    } catch (err) {
      setError(err.message || 'Failed to load articles.');
    } finally {
      setLoading(false);
    }
  }
  useEffectJA(() => { if (token) refresh(); }, [token]);

  async function removeArticle(a) {
    if (!confirm(`Delete "${a.title}"?\n\nThis cannot be undone.`)) return;
    setDeleting(a.id);
    try {
      await api(`/api/admin/journal/${encodeURIComponent(a.id)}`, { method: 'DELETE' });
      setArticles(prev => prev.filter(x => x.id !== a.id));
      if (typeof window.refreshArticles === 'function') window.refreshArticles();
    } catch (err) {
      alert(err.message || 'Could not delete.');
    } finally {
      setDeleting(null);
    }
  }

  async function toggleStatus(a) {
    const next = a.status === 'draft' ? 'published' : 'draft';
    try {
      const fd = new FormData();
      fd.append('status', next);
      const d = await api(`/api/admin/journal/${encodeURIComponent(a.id)}`, { method: 'PATCH', body: fd });
      setArticles(prev => prev.map(x => x.id === a.id ? d.article : x));
      if (typeof window.refreshArticles === 'function') window.refreshArticles();
    } catch (err) {
      alert(err.message || 'Could not change status.');
    }
  }

  function onSaved(saved, isNew) {
    setArticles(prev => {
      if (isNew) return [saved, ...prev];
      return prev.map(x => x.id === saved.id ? saved : x);
    });
    setEditing(null);
    if (typeof window.refreshArticles === 'function') window.refreshArticles();
  }

  if (editing) {
    return (
      <ArticleEditor
        token={token}
        onUnauthorized={onUnauthorized}
        article={editing.__new ? null : editing}
        onCancel={() => setEditing(null)}
        onSaved={onSaved}
      />
    );
  }

  return (
    <div style={{ maxWidth: '960px' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', marginBottom: '20px', gap: '16px', flexWrap: 'wrap' }}>
        <div>
          <p className="t-label" style={{ color: 'var(--terracotta)', marginBottom: '8px' }}>Catalogue settings</p>
          <h2 style={{ fontFamily: 'var(--serif)', fontWeight: 300, fontSize: '32px', marginBottom: '8px' }}>Journal</h2>
          <p style={{ fontFamily: 'var(--sans)', fontSize: '13px', color: 'var(--dark-mid)', lineHeight: 1.6, maxWidth: '560px' }}>
            Write, edit, hide or remove editorial posts. Drafts stay invisible on the public site until you publish them.
          </p>
        </div>
        <button
          type="button"
          onClick={() => setEditing({ __new: true })}
          className="btn btn-dark"
          style={{ padding: '12px 22px' }}
        >+ New article</button>
      </div>

      {error && <p style={{ fontFamily: 'var(--sans)', fontSize: '12px', color: 'var(--terracotta)', marginBottom: '14px' }}>{error}</p>}

      {loading ? (
        <p style={{ padding: '40px 0', fontFamily: 'var(--sans)', fontSize: '13px', color: 'var(--dark-mid)' }}>Loading articles…</p>
      ) : articles.length === 0 ? (
        <div style={{ border: '1px solid var(--cream-deep)', padding: '40px', textAlign: 'center', background: 'white' }}>
          <p style={{ fontFamily: 'var(--serif)', fontSize: '20px', fontWeight: 300, marginBottom: '8px' }}>No articles yet</p>
          <p style={{ fontFamily: 'var(--sans)', fontSize: '13px', color: 'var(--dark-mid)' }}>Click "New article" above to publish your first journal post.</p>
        </div>
      ) : (
        <div style={{ border: '1px solid var(--cream-deep)', background: 'white' }}>
          {articles.map((a, idx) => (
            <div key={a.id} style={{
              display: 'grid', gridTemplateColumns: '88px 1fr auto', gap: '16px',
              padding: '14px 16px',
              borderBottom: idx < articles.length - 1 ? '1px solid var(--cream-deep)' : 'none',
              alignItems: 'center',
            }}>
              <div style={{ aspectRatio: '1', overflow: 'hidden', background: 'var(--cream-deep)' }}>
                {a.thumb || a.hero ? (
                  <img src={a.thumb || a.hero} alt="" style={{ width: '100%', height: '100%', objectFit: 'cover' }} onError={e => e.target.style.display = 'none'}/>
                ) : null}
              </div>
              <div style={{ minWidth: 0 }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: '8px', marginBottom: '4px' }}>
                  <p style={{ fontFamily: 'var(--serif)', fontSize: '17px', fontWeight: 400 }}>{a.title}</p>
                  <span style={{
                    fontFamily: 'var(--sans)', fontSize: '9px', fontWeight: 500,
                    letterSpacing: '0.16em', textTransform: 'uppercase',
                    padding: '2px 8px',
                    background: a.status === 'draft' ? '#FAE3B5' : 'rgba(60, 130, 80, 0.12)',
                    color: a.status === 'draft' ? '#8a6520' : '#3c8250',
                  }}>{a.status || 'published'}</span>
                </div>
                <p style={{ fontFamily: 'var(--sans)', fontSize: '11px', color: 'var(--dark-mid)', letterSpacing: '0.08em' }}>
                  {[a.category, a.date, a.read].filter(Boolean).join(' · ')}
                </p>
              </div>
              <div style={{ display: 'flex', gap: '6px', flexShrink: 0 }}>
                <button type="button" onClick={() => toggleStatus(a)} style={smallBtn}>{a.status === 'draft' ? 'Publish' : 'Unpublish'}</button>
                <button type="button" onClick={() => setEditing(a)} style={smallBtn}>Edit</button>
                <button type="button" onClick={() => removeArticle(a)} disabled={deletingId === a.id} style={{ ...smallBtn, color: 'var(--terracotta)' }}>
                  {deletingId === a.id ? '…' : 'Delete'}
                </button>
              </div>
            </div>
          ))}
        </div>
      )}
    </div>
  );
}

// ─── ArticleEditor ─────────────────────────────────────────────────────
// Form panel for create + edit. Shared because the only difference
// between modes is whether the PATCH or POST is fired on Save.
function ArticleEditor({ token, onUnauthorized, article, onCancel, onSaved }) {
  const isNew = !article;
  const [form, setForm] = useStateJA(() => ({
    title:    article?.title    || '',
    category: article?.category || '',
    date:     article?.date     || defaultMonthLabel(),
    read:     article?.read     || '5 min read',
    intro:    article?.intro    || '',
    body:     article?.body     || '',
    status:   article?.status   || 'published',
  }));
  const [heroFile, setHeroFile] = useStateJA(null);
  const [saving, setSaving]     = useStateJA(false);
  const [error, setError]       = useStateJA(null);
  const fileRef = useRefJA(null);

  const set = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));

  async function handleSubmit(e) {
    e.preventDefault();
    if (!form.title.trim()) { setError('Title is required.'); return; }
    setSaving(true);
    setError(null);
    try {
      const fd = new FormData();
      Object.entries(form).forEach(([k, v]) => fd.append(k, String(v ?? '')));
      if (heroFile) fd.append('hero', heroFile);
      const url = isNew
        ? '/api/admin/journal'
        : `/api/admin/journal/${encodeURIComponent(article.id)}`;
      const r = await fetch(url, {
        method: isNew ? 'POST' : 'PATCH',
        headers: { Authorization: `Bearer ${token}` },
        body: fd,
      });
      if (r.status === 401) { onUnauthorized?.(); throw new Error('Session expired.'); }
      const d = await r.json().catch(() => ({}));
      if (!r.ok) throw new Error(d.error || `HTTP ${r.status}`);
      onSaved?.(d.article, isNew);
    } catch (err) {
      setError(err.message || 'Save failed.');
    } finally {
      setSaving(false);
    }
  }

  const existingHero = article?.hero || article?.thumb || '';

  return (
    <form onSubmit={handleSubmit} style={{ maxWidth: '780px' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: '14px', marginBottom: '24px' }}>
        <button type="button" onClick={onCancel} style={{
          background: 'none', border: 'none', cursor: 'pointer',
          fontFamily: 'var(--sans)', fontSize: '11px', color: 'var(--dark-mid)',
          letterSpacing: '0.14em', textTransform: 'uppercase', padding: 0,
        }}>← Back to articles</button>
        <span style={{ flex: 1 }}/>
      </div>

      <p className="t-label" style={{ color: 'var(--terracotta)', marginBottom: '8px' }}>{isNew ? 'New article' : 'Edit article'}</p>
      <h2 style={{ fontFamily: 'var(--serif)', fontWeight: 300, fontSize: '32px', marginBottom: '32px' }}>
        {isNew ? 'Write a new journal post' : form.title || 'Untitled'}
      </h2>

      <div style={{ display: 'grid', gap: '20px' }}>
        <div>
          <label>Title</label>
          <input type="text" value={form.title} onChange={set('title')} required maxLength={140}/>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '14px' }}>
          <div>
            <label>Category</label>
            <input type="text" value={form.category} onChange={set('category')} placeholder="Outdoor · Floor · Studio…" maxLength={60}/>
          </div>
          <div>
            <label>Date label</label>
            <input type="text" value={form.date} onChange={set('date')} placeholder="May 2026" maxLength={40}/>
          </div>
          <div>
            <label>Read time</label>
            <input type="text" value={form.read} onChange={set('read')} placeholder="5 min read" maxLength={40}/>
          </div>
        </div>

        <div>
          <label>Hero image</label>
          {existingHero && !heroFile && (
            <div style={{ display: 'flex', alignItems: 'center', gap: '14px', marginBottom: '10px' }}>
              <img src={existingHero} alt="" style={{ width: '120px', height: '90px', objectFit: 'cover', background: 'var(--cream-deep)' }}/>
              <p style={{ fontFamily: 'var(--sans)', fontSize: '11px', color: 'var(--dark-mid)' }}>
                Current hero — leave file picker empty to keep this image.
              </p>
            </div>
          )}
          <input
            ref={fileRef}
            type="file"
            accept="image/*"
            onChange={e => setHeroFile(e.target.files?.[0] || null)}
            style={{ padding: '8px' }}
          />
          {heroFile && (
            <p style={{ fontFamily: 'var(--sans)', fontSize: '11px', color: 'var(--dark-mid)', marginTop: '6px' }}>
              New: {heroFile.name} ({Math.round(heroFile.size/1024)} KB) · <button type="button" onClick={() => { setHeroFile(null); if (fileRef.current) fileRef.current.value = ''; }} style={{ background: 'none', border: 'none', color: 'var(--terracotta)', cursor: 'pointer', padding: 0, fontFamily: 'inherit', fontSize: 'inherit' }}>clear</button>
            </p>
          )}
        </div>

        <div>
          <label>Intro (italic deck)</label>
          <textarea value={form.intro} onChange={set('intro')} rows={3} maxLength={400} placeholder="One or two sentences shown under the headline."/>
        </div>

        <div>
          <label>Body</label>
          <textarea
            value={form.body}
            onChange={set('body')}
            rows={16}
            placeholder="Full article. Separate paragraphs with a blank line."
            style={{ fontFamily: 'var(--sans)', lineHeight: 1.7 }}
          />
          <p style={{ fontFamily: 'var(--sans)', fontSize: '11px', color: 'var(--dark-mid)', marginTop: '6px' }}>
            Tip: a blank line between paragraphs becomes a new paragraph on the site.
          </p>
        </div>

        <div>
          <label>Status</label>
          <div style={{ display: 'flex', gap: '8px' }}>
            {[
              { id: 'published', label: 'Published' },
              { id: 'draft',     label: 'Draft (hidden)' },
            ].map(opt => (
              <button
                key={opt.id}
                type="button"
                onClick={() => setForm(f => ({ ...f, status: opt.id }))}
                style={{
                  padding: '9px 16px', cursor: 'pointer',
                  background: form.status === opt.id ? 'var(--dark)' : 'white',
                  color:      form.status === opt.id ? 'white' : 'var(--dark-mid)',
                  border: '1px solid var(--cream-deep)',
                  fontFamily: 'var(--sans)', fontSize: '11px',
                  letterSpacing: '0.12em', textTransform: 'uppercase',
                }}
              >{opt.label}</button>
            ))}
          </div>
        </div>

        {error && <p style={{ fontFamily: 'var(--sans)', fontSize: '12px', color: 'var(--terracotta)' }}>{error}</p>}

        <div style={{ display: 'flex', gap: '12px', marginTop: '12px' }}>
          <button type="submit" className="btn btn-dark" disabled={saving} style={{ opacity: saving ? 0.6 : 1, padding: '14px 26px' }}>
            {saving ? 'Saving…' : (isNew ? 'Publish article' : 'Save changes')}
          </button>
          <button type="button" onClick={onCancel} className="btn btn-outline">Cancel</button>
        </div>
      </div>
    </form>
  );
}

function defaultMonthLabel() {
  const d = new Date();
  return d.toLocaleString('en-GB', { month: 'long', year: 'numeric' });
}

const smallBtn = {
  padding: '7px 12px',
  background: 'white', border: '1px solid var(--cream-deep)',
  color: 'var(--dark)',
  fontFamily: 'var(--sans)', fontSize: '10px',
  letterSpacing: '0.1em', textTransform: 'uppercase',
  cursor: 'pointer',
};

Object.assign(window, { JournalAdmin });
