// ─── Helpers ──────────────────────────────────────────────────────────────────

const slugify = (s) =>
  s.toLowerCase().trim().replace(/[^a-z0-9]+/g, '-').replace(/^-|-$/g, '');

const BLANK = () => ({
  slug: '', status: 'draft', featured: false,
  title:            i18nBlank(),
  excerpt:          i18nBlank(),
  content:          i18nBlank(),
  meta_title:       i18nBlank(),
  meta_description: i18nBlank(),
  cover_url: '', og_image: '', category: '', tags: [], reading_time: 5,
});

const BLOG_LANGS = [
  { id: 'en',     label: 'EN',  name: 'English'  },
  { id: 'fr',     label: 'FR',  name: 'Français' },
  { id: 'darija', label: 'DAR', name: 'Darija'   },
];

// ─── Toast ────────────────────────────────────────────────────────────────────

function BlogToast({ toast }) {
  if (!toast) return null;
  const ok = toast.type === 'success';
  return (
    <div style={{
      position: 'fixed', top: 24, right: 24, zIndex: 9999,
      background: ok ? '#16a34a' : '#dc2626',
      color: '#fff', padding: '10px 18px', borderRadius: 8,
      fontSize: 'var(--fs-body-sm)', fontWeight: 'var(--fw-medium)',
      boxShadow: '0 4px 16px rgba(0,0,0,.2)',
    }}>
      {toast.msg}
    </div>
  );
}

// ─── Delete confirm modal ─────────────────────────────────────────────────────

function DeleteConfirm({ title, onConfirm, onCancel }) {
  return (
    <div className="detail-modal-overlay" onClick={onCancel}>
      <div className="detail-modal" style={{ maxWidth: 400 }} onClick={e => e.stopPropagation()}>
        <div className="detail-modal__head">
          <div className="detail-modal__title">Delete post?</div>
        </div>
        <div className="detail-modal__body">
          <p style={{ color: 'var(--fg-secondary)', fontSize: 'var(--fs-body-sm)' }}>
            "{title}" will be permanently deleted. This cannot be undone.
          </p>
        </div>
        <div className="detail-modal__actions">
          <button className="btn btn--ghost" onClick={onCancel}>Cancel</button>
          <button className="btn btn--danger" onClick={onConfirm}>Delete</button>
        </div>
      </div>
    </div>
  );
}

// ─── List view ────────────────────────────────────────────────────────────────

function BlogList({ posts, onNew, onEdit, onDelete, onToggleFeatured }) {
  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 'var(--space-6)' }}>
        <div>
          <h1 className="page-title">Blog</h1>
          <p className="page-subtitle">{posts.length} post{posts.length !== 1 ? 's' : ''}</p>
        </div>
        <button className="btn btn--primary" onClick={onNew}>+ New Post</button>
      </div>

      {posts.length === 0 ? (
        <div style={{ textAlign: 'center', padding: '60px 20px', color: 'var(--fg-secondary)' }}>
          <p style={{ marginBottom: 16 }}>No posts yet.</p>
          <button className="btn btn--primary" onClick={onNew}>Create your first post</button>
        </div>
      ) : (
        <div className="table-wrap">
          <table className="table">
            <thead>
              <tr>
                <th>Title</th>
                <th>Category</th>
                <th>Status</th>
                <th>Featured</th>
                <th>Date</th>
                <th style={{ textAlign: 'right' }}>Actions</th>
              </tr>
            </thead>
            <tbody>
              {posts.map(p => (
                <tr key={p.id}>
                  <td style={{ fontWeight: 'var(--fw-medium)', maxWidth: 280 }}>
                    <span style={{ display: 'block', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {i18nOf(p.title, 'en') || <em style={{ color: 'var(--fg-secondary)' }}>(no title)</em>}
                    </span>
                    <span style={{ fontSize: 'var(--fs-caption)', color: 'var(--fg-secondary)' }}>{p.slug}</span>
                  </td>
                  <td style={{ fontSize: 'var(--fs-body-sm)', color: 'var(--fg-secondary)' }}>{p.category || '—'}</td>
                  <td>
                    <span className={`pill pill--${p.status === 'published' ? 'completed' : 'new'}`}>
                      {p.status}
                    </span>
                  </td>
                  <td>
                    <button
                      className="btn btn--ghost"
                      style={{ fontSize: 'var(--fs-caption)', padding: '3px 8px', color: p.featured ? '#f97316' : 'var(--fg-secondary)' }}
                      onClick={() => onToggleFeatured(p)}
                      title={p.featured ? 'Remove from featured' : 'Mark as featured'}
                    >
                      {p.featured ? '★ Featured' : '☆ Feature'}
                    </button>
                  </td>
                  <td style={{ fontSize: 'var(--fs-caption)', color: 'var(--fg-secondary)', whiteSpace: 'nowrap' }}>
                    {new Date(p.created_at).toLocaleDateString('en-US', { month: 'short', day: 'numeric', year: 'numeric' })}
                  </td>
                  <td>
                    <div style={{ display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
                      <button className="btn btn--ghost" style={{ fontSize: 'var(--fs-caption)', padding: '4px 10px' }} onClick={() => onEdit(p)}>Edit</button>
                      <button className="btn btn--danger" style={{ fontSize: 'var(--fs-caption)', padding: '4px 10px' }} onClick={() => onDelete(p)}>Delete</button>
                    </div>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

// ─── Tag input ────────────────────────────────────────────────────────────────

function TagInput({ value = [], onChange }) {
  const [draft, setDraft] = React.useState('');

  const add = () => {
    const tag = draft.trim().toLowerCase().replace(/\s+/g, '-');
    if (tag && !value.includes(tag)) onChange([...value, tag]);
    setDraft('');
  };

  const remove = (t) => onChange(value.filter(x => x !== t));

  return (
    <div className="tag-input">
      <div className="tag-input__pills">
        {value.map(t => (
          <span key={t} className="tag-pill">
            {t}
            <button type="button" className="tag-pill__remove" onClick={() => remove(t)}>×</button>
          </span>
        ))}
        <input
          className="tag-input__field"
          value={draft}
          onChange={e => setDraft(e.target.value)}
          onKeyDown={e => {
            if (e.key === 'Enter')     { e.preventDefault(); add(); }
            if (e.key === 'Backspace' && !draft && value.length) remove(value[value.length - 1]);
          }}
          placeholder={value.length ? '' : 'Type a tag + Enter'}
        />
      </div>
    </div>
  );
}

// ─── Category select ──────────────────────────────────────────────────────────

function CategorySelect({ value, onChange, categories, onCreate }) {
  const [mode, setMode] = React.useState('select');
  const [draft, setDraft] = React.useState('');
  const [busy,  setBusy]  = React.useState(false);

  const handleCreate = async () => {
    const name = draft.trim();
    if (!name || busy) return;
    setBusy(true);
    const created = await onCreate(name);
    setBusy(false);
    if (created) { onChange(created); setMode('select'); setDraft(''); }
  };

  if (mode === 'new') {
    return (
      <div style={{ display: 'flex', gap: 6 }}>
        <input
          className="input"
          value={draft}
          onChange={e => setDraft(e.target.value)}
          placeholder="Category name"
          autoFocus
          onKeyDown={e => { if (e.key === 'Enter') handleCreate(); if (e.key === 'Escape') setMode('select'); }}
          style={{ flex: 1 }}
        />
        <button className="btn btn--primary" onClick={handleCreate} disabled={busy} style={{ padding: '0 12px', fontSize: 'var(--fs-caption)' }}>
          {busy ? '…' : 'Add'}
        </button>
        <button className="btn btn--ghost" onClick={() => setMode('select')} style={{ padding: '0 10px', fontSize: 'var(--fs-caption)' }}>
          ✕
        </button>
      </div>
    );
  }

  return (
    <div style={{ display: 'flex', gap: 6 }}>
      <select className="input" value={value} onChange={e => onChange(e.target.value)} style={{ flex: 1 }}>
        <option value="">No category</option>
        {categories.map(c => <option key={c.id} value={c.name}>{c.name}</option>)}
      </select>
      <button className="btn btn--ghost" onClick={() => setMode('new')} style={{ padding: '0 10px', fontSize: 'var(--fs-caption)', whiteSpace: 'nowrap' }}>
        + New
      </button>
    </div>
  );
}

// ─── Sanitize ─────────────────────────────────────────────────────────────────

const sanitize = (html) =>
  html
    .replace(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/gi, '')
    .replace(/\son\w+="[^"]*"/gi, '');

// ─── Paste cleaner ────────────────────────────────────────────────────────────
// Strips Google Docs / Word cruft while keeping semantic formatting.

function cleanPastedHtml(html) {
  const doc  = new DOMParser().parseFromString(html, 'text/html');
  const body = doc.body;

  // Google Docs wraps the entire paste in a root <b> — unwrap it
  const outerB = body.querySelector(':scope > b');
  if (outerB) {
    while (outerB.firstChild) body.insertBefore(outerB.firstChild, outerB);
    outerB.remove();
  }

  // Convert styled <span>s to semantic elements (reverse = deepest first)
  [...body.querySelectorAll('span')].reverse().forEach(span => {
    const s      = span.getAttribute('style') || '';
    const bold   = /font-weight\s*:\s*(bold|[6-9]\d{2})/i.test(s);
    const italic = /font-style\s*:\s*italic/i.test(s);
    let replacement;
    if (bold && italic) {
      const strong = doc.createElement('strong');
      const em     = doc.createElement('em');
      strong.appendChild(em);
      while (span.firstChild) em.appendChild(span.firstChild);
      replacement = strong;
    } else if (bold) {
      const strong = doc.createElement('strong');
      while (span.firstChild) strong.appendChild(span.firstChild);
      replacement = strong;
    } else if (italic) {
      const em = doc.createElement('em');
      while (span.firstChild) em.appendChild(span.firstChild);
      replacement = em;
    }
    if (replacement) span.replaceWith(replacement);
    else             span.replaceWith(...Array.from(span.childNodes));
  });

  // Strip disallowed attributes; fix Google redirect links
  const KEEP = { A: ['href','target','rel'], IMG: ['src','alt'] };
  body.querySelectorAll('*').forEach(el => {
    const keep = KEEP[el.tagName] || [];
    [...el.attributes].forEach(attr => {
      if (!keep.includes(attr.name)) el.removeAttribute(attr.name);
    });
    if (el.tagName === 'A') {
      const href = el.getAttribute('href') || '';
      if (href.includes('google.com/url')) {
        try { const real = new URL(href).searchParams.get('q'); if (real) el.setAttribute('href', real); } catch {}
      }
      el.setAttribute('target', '_blank');
      el.setAttribute('rel', 'noopener noreferrer');
    }
  });

  // Unwrap disallowed elements (keep their children), deepest first
  const ALLOWED = new Set([
    'p','br','hr','strong','em','b','i',
    'h1','h2','h3','h4','h5','h6',
    'ul','ol','li','a','blockquote','pre','code','img',
  ]);
  [...body.querySelectorAll('*')].reverse().forEach(el => {
    if (!ALLOWED.has(el.tagName.toLowerCase())) {
      el.replaceWith(...Array.from(el.childNodes));
    }
  });

  // Remove empty paragraphs left behind
  body.querySelectorAll('p').forEach(p => { if (!p.innerHTML.trim()) p.remove(); });

  return body.innerHTML;
}

// ─── Editor inline modals ────────────────────────────────────────────────────

function EditorLinkModal({ onInsert, onClose }) {
  const [url, setUrl] = React.useState('https://');
  return (
    <div className="editor-modal">
      <div className="blog-section-label" style={{ marginBottom: 'var(--space-3)' }}>Insert Link</div>
      <input
        className="input"
        value={url}
        onChange={e => setUrl(e.target.value)}
        placeholder="https://"
        autoFocus
        onKeyDown={e => { if (e.key === 'Enter') onInsert(url); if (e.key === 'Escape') onClose(); }}
      />
      <div style={{ display: 'flex', gap: 8, marginTop: 'var(--space-3)', justifyContent: 'flex-end' }}>
        <button className="btn btn--ghost" onClick={onClose} style={{ fontSize: 'var(--fs-caption)', padding: '4px 12px' }}>Cancel</button>
        <button className="btn btn--primary" onClick={() => onInsert(url)} disabled={!url || url === 'https://'} style={{ fontSize: 'var(--fs-caption)', padding: '4px 12px' }}>Insert</button>
      </div>
    </div>
  );
}

function EditorImageModal({ onInsert, onClose }) {
  const [tab, setTab] = React.useState('upload');
  const [src, setSrc] = React.useState('');
  return (
    <div className="editor-modal">
      <div className="blog-section-label" style={{ marginBottom: 'var(--space-3)' }}>Insert Image</div>
      <div className="tab-bar" style={{ marginBottom: 'var(--space-4)' }}>
        <button className={`tab${tab === 'upload' ? ' active' : ''}`} onClick={() => setTab('upload')}>Upload</button>
        <button className={`tab${tab === 'url' ? ' active' : ''}`} onClick={() => setTab('url')}>URL</button>
      </div>
      {tab === 'upload'
        ? <ImageUpload value={src} onChange={setSrc} uploadLabel="Upload image" />
        : <input className="input" value={src} onChange={e => setSrc(e.target.value)} placeholder="https://…" autoFocus onKeyDown={e => { if (e.key === 'Escape') onClose(); }} />
      }
      <div style={{ display: 'flex', gap: 8, marginTop: 'var(--space-3)', justifyContent: 'flex-end' }}>
        <button className="btn btn--ghost" onClick={onClose} style={{ fontSize: 'var(--fs-caption)', padding: '4px 12px' }}>Cancel</button>
        <button className="btn btn--primary" onClick={() => src && onInsert(src)} disabled={!src} style={{ fontSize: 'var(--fs-caption)', padding: '4px 12px' }}>Insert</button>
      </div>
    </div>
  );
}

// ─── Rich text toolbar ────────────────────────────────────────────────────────

function RichToolbar({ editorRef, onLink, onImage }) {
  // e.preventDefault() on mousedown keeps focus in editor so execCommand works
  const cmd = (e, command, value) => {
    e.preventDefault();
    editorRef.current?.focus();
    document.execCommand(command, false, value || null);
  };

  const insertCode = (e) => {
    e.preventDefault();
    editorRef.current?.focus();
    const sel = window.getSelection()?.toString() || '';
    document.execCommand('insertHTML', false,
      `<pre><code>${sel || 'code here'}</code></pre>`
    );
  };

  return (
    <div className="rich-toolbar">
      <button type="button" className="rich-toolbar__btn rich-toolbar__btn--b"  title="Bold"           onMouseDown={e => cmd(e, 'bold')}>B</button>
      <button type="button" className="rich-toolbar__btn rich-toolbar__btn--i"  title="Italic"         onMouseDown={e => cmd(e, 'italic')}>I</button>
      <div className="rich-toolbar__sep" />
      <button type="button" className="rich-toolbar__btn" title="Heading 1"     onMouseDown={e => cmd(e, 'formatBlock', 'h1')}>H1</button>
      <button type="button" className="rich-toolbar__btn" title="Heading 2"     onMouseDown={e => cmd(e, 'formatBlock', 'h2')}>H2</button>
      <button type="button" className="rich-toolbar__btn" title="Heading 3"     onMouseDown={e => cmd(e, 'formatBlock', 'h3')}>H3</button>
      <div className="rich-toolbar__sep" />
      <button type="button" className="rich-toolbar__btn" title="Bullet list"   onMouseDown={e => cmd(e, 'insertUnorderedList')}>≡</button>
      <button type="button" className="rich-toolbar__btn" title="Numbered list" onMouseDown={e => cmd(e, 'insertOrderedList')}>1.</button>
      <div className="rich-toolbar__sep" />
      <button type="button" className="rich-toolbar__btn" title="Link"          onMouseDown={e => { e.preventDefault(); onLink(); }}>↗</button>
      <button type="button" className="rich-toolbar__btn" title="Image"         onMouseDown={e => { e.preventDefault(); onImage(); }}>⬚</button>
      <div className="rich-toolbar__sep" />
      <button type="button" className="rich-toolbar__btn" title="Code block"    onMouseDown={insertCode}>&lt;/&gt;</button>
      <button type="button" className="rich-toolbar__btn" title="Blockquote"    onMouseDown={e => cmd(e, 'formatBlock', 'blockquote')}>"</button>
    </div>
  );
}

// ─── Content editor (contentEditable + toolbar + preview) ────────────────────

function ContentEditor({ i18nValue, lang, onI18nChange, placeholder }) {
  const [mode,  setMode]  = React.useState('edit');
  const [modal, setModal] = React.useState(null); // null | 'link' | 'image'
  const editorRef    = React.useRef(null);
  const savedRange   = React.useRef(null);

  // Populate editor on mount and on lang/mode change
  React.useEffect(() => {
    if (mode === 'edit' && editorRef.current) {
      editorRef.current.innerHTML = i18nOf(i18nValue, lang) || '';
    }
  }, [lang, mode]); // i18nValue intentionally omitted — controlled by onInput

  const handleInput = () => {
    if (!editorRef.current) return;
    let html = editorRef.current.innerHTML;
    if (html === '<br>' || html === '<br/>') html = '';
    onI18nChange(i18nSet(i18nValue, lang, sanitize(html)));
  };

  const saveSelection = () => {
    const sel = window.getSelection();
    if (sel?.rangeCount > 0) savedRange.current = sel.getRangeAt(0).cloneRange();
  };

  const openModal = (type) => {
    saveSelection();
    setModal(type);
  };

  // Close modal on ESC
  React.useEffect(() => {
    if (!modal) return;
    const onKey = (e) => { if (e.key === 'Escape') setModal(null); };
    document.addEventListener('keydown', onKey);
    return () => document.removeEventListener('keydown', onKey);
  }, [modal]);

  // Insert link via Range API — no execCommand, no browser dialog
  const handleInsertLink = (url) => {
    setModal(null);
    requestAnimationFrame(() => {
      const range = savedRange.current;
      if (!range) return;
      editorRef.current?.focus();

      const a = document.createElement('a');
      a.href = url;
      a.target = '_blank';
      a.rel = 'noopener noreferrer';
      a.textContent = range.toString().trim() || url;

      range.deleteContents();
      range.insertNode(a);

      // Move cursor past the inserted link
      const after = document.createRange();
      after.setStartAfter(a);
      after.collapse(true);
      const sel = window.getSelection();
      sel.removeAllRanges();
      sel.addRange(after);

      handleInput();
    });
  };

  // Insert image via Range API — no execCommand, no browser dialog
  const handleInsertImage = (src) => {
    setModal(null);
    requestAnimationFrame(() => {
      const range = savedRange.current;
      if (!range) return;
      editorRef.current?.focus();

      const img = document.createElement('img');
      img.src = src;
      img.alt = '';
      img.style.cssText = 'max-width:100%;border-radius:8px;display:block;margin:8px 0;';

      range.deleteContents();
      range.insertNode(img);

      // Move cursor past the inserted image
      const after = document.createRange();
      after.setStartAfter(img);
      after.collapse(true);
      const sel = window.getSelection();
      sel.removeAllRanges();
      sel.addRange(after);

      handleInput();
    });
  };

  const handlePaste = (e) => {
    e.preventDefault();
    const html  = e.clipboardData.getData('text/html');
    const plain = e.clipboardData.getData('text/plain');
    const insert = html
      ? cleanPastedHtml(html)
      : plain.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/\n/g,'<br>');
    if (!insert) return;
    document.execCommand('insertHTML', false, insert);
    handleInput();
  };

  const isEmpty = !i18nOf(i18nValue, lang);

  return (
    <div style={{ position: 'relative' }}>
      <div style={{ display: 'flex', justifyContent: 'flex-end', marginBottom: 'var(--space-2)' }}>
        <div className="tab-bar" style={{ marginBottom: 0 }}>
          <button className={`tab${mode === 'edit' ? ' active' : ''}`} onClick={() => setMode('edit')}>Edit</button>
          <button className={`tab${mode === 'preview' ? ' active' : ''}`} onClick={() => setMode('preview')}>Preview</button>
        </div>
      </div>

      {mode === 'edit' ? (
        <>
          <RichToolbar editorRef={editorRef} onLink={() => openModal('link')} onImage={() => openModal('image')} />
          <div
            ref={editorRef}
            className={`blog-editor${isEmpty ? ' blog-editor--empty' : ''}`}
            contentEditable
            suppressContentEditableWarning
            onInput={handleInput}
            onPaste={handlePaste}
            data-placeholder={placeholder || 'Start writing your content…'}
          />
          {modal && <div style={{ position: 'fixed', inset: 0, zIndex: 19 }} onClick={() => setModal(null)} />}
          {modal === 'link'  && <EditorLinkModal  onInsert={handleInsertLink}  onClose={() => setModal(null)} />}
          {modal === 'image' && <EditorImageModal onInsert={handleInsertImage} onClose={() => setModal(null)} />}
        </>
      ) : (
        <div
          className="blog-preview-pane"
          dangerouslySetInnerHTML={{ __html: i18nOf(i18nValue, lang) || '<em style="color:var(--fg-secondary)">Nothing to preview.</em>' }}
        />
      )}
    </div>
  );
}

// ─── Form view ────────────────────────────────────────────────────────────────

function BlogForm({ initial, onSave, onCancel, saving, categories, onCreateCategory }) {
  const [form, setForm]               = React.useState(initial || BLANK());
  const [lang, setLang]               = React.useState('en');
  const [slugTouched, setSlugTouched] = React.useState(!!initial);
  const [errors, setErrors]           = React.useState({});

  const set = (key, val) => setForm(f => ({ ...f, [key]: val }));

  const handleEnTitleChange = (e) => {
    const val = e.target.value;
    set('title', i18nSet(form.title, 'en', val));
    if (!slugTouched) set('slug', slugify(val));
  };

  const handleSlugChange = (e) => {
    setSlugTouched(true);
    set('slug', slugify(e.target.value));
  };

  const handleSave = () => {
    const errs = {};
    if (!i18nOf(form.title, 'en').trim()) errs.titleEn = 'English title is required';
    if (!form.slug.trim())               errs.slug    = 'Slug is required';
    if (Object.keys(errs).length) { setErrors(errs); return; }
    setErrors({});
    onSave(form);
  };

  const handlePreview = () => {
    sessionStorage.setItem('blog_preview', JSON.stringify(form));
    window.open('../web/blog.html?slug=__preview__', '_blank');
  };

  const isEmpty    = (field, l) => !i18nOf(form[field], l).trim();
  const activeLang = BLOG_LANGS.find(l => l.id === lang);

  return (
    <div>

      {/* ── Header ─────────────────────────────────────────────────────────── */}
      <div style={{ display: 'flex', alignItems: 'center', gap: 'var(--space-4)', marginBottom: 'var(--space-6)', flexWrap: 'wrap' }}>
        <button className="btn btn--ghost" onClick={onCancel} style={{ fontSize: 'var(--fs-body-sm)' }}>← All Posts</button>
        <h1 className="page-title" style={{ flex: 1, marginBottom: 0 }}>{initial ? 'Edit Post' : 'New Post'}</h1>
        <button className="btn btn--ghost" onClick={handlePreview}>Preview</button>
        <button className="btn btn--primary" onClick={handleSave} disabled={saving}>
          {saving ? 'Saving…' : 'Save Post'}
        </button>
      </div>

      <div className="blog-form-grid">

        {/* ── Main column ──────────────────────────────────────────────────── */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-5)' }}>

          {/* Content */}
          <div className="card" style={{ padding: 'var(--space-5)' }}>
            <div style={{ display: 'flex', alignItems: 'flex-start', justifyContent: 'space-between', marginBottom: 'var(--space-5)', gap: 'var(--space-3)', flexWrap: 'wrap' }}>
              <div>
                <div className="blog-section-label" style={{ marginBottom: 2 }}>Content</div>
                <div style={{ fontSize: 'var(--fs-caption)', color: 'var(--fg-secondary)' }}>Editing: {activeLang.name}</div>
              </div>
              <div className="tab-bar" style={{ marginBottom: 0 }}>
                {BLOG_LANGS.map(l => (
                  <button key={l.id} className={`tab${lang === l.id ? ' active' : ''}`} onClick={() => setLang(l.id)}>
                    {l.label}
                    {l.id !== 'en' && (isEmpty('title', l.id) || isEmpty('content', l.id)) && (
                      <span style={{ marginLeft: 4, color: '#f97316', fontSize: 9, lineHeight: 1 }}>●</span>
                    )}
                  </button>
                ))}
              </div>
            </div>

            {/* Title per-lang */}
            <div className="blog-field">
              <label className="blog-field-label" style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                Title
                {lang !== 'en' && isEmpty('title', lang) && <span className="blog-not-translated">Not translated</span>}
              </label>
              <I18nInput
                value={form.title}
                lang={lang}
                onChange={val => {
                  set('title', val);
                  if (lang === 'en' && !slugTouched) set('slug', slugify(val.en || ''));
                }}
                placeholder={`Title in ${activeLang.name}`}
                className={`input${errors.titleEn && lang === 'en' ? ' blog-input--error' : ''}`}
              />
              {errors.titleEn && lang === 'en' && <p className="blog-field-error">{errors.titleEn}</p>}
            </div>

            {/* Excerpt per-lang */}
            <div className="blog-field" style={{ marginTop: 'var(--space-4)' }}>
              <label className="blog-field-label" style={{ display: 'flex', alignItems: 'center', gap: 6 }}>
                Excerpt
                {lang !== 'en' && isEmpty('excerpt', lang) && <span className="blog-not-translated">Not translated</span>}
              </label>
              <I18nTextarea value={form.excerpt} lang={lang} onChange={val => set('excerpt', val)} placeholder="Short description (1–2 sentences)" className="textarea" rows={3} />
            </div>

            {/* Content per-lang — rich editor */}
            <div style={{ marginTop: 'var(--space-4)' }}>
              <label className="blog-field-label" style={{ display: 'flex', alignItems: 'center', gap: 6, marginBottom: 'var(--space-2)' }}>
                Content — HTML
                {lang !== 'en' && isEmpty('content', lang) && <span className="blog-not-translated">Not translated</span>}
              </label>
              <ContentEditor
                i18nValue={form.content}
                lang={lang}
                onI18nChange={val => set('content', val)}
                placeholder={'<h2>Section</h2>\n<p>Write your content here…</p>'}
              />
            </div>
          </div>

          {/* SEO */}
          <div className="card" style={{ padding: 'var(--space-5)' }}>
            <div className="blog-section-label">SEO — {activeLang.name}</div>

            <div className="blog-field">
              <label className="blog-field-label">Meta Title</label>
              <I18nInput value={form.meta_title} lang={lang} onChange={val => set('meta_title', val)} placeholder={`SEO title in ${activeLang.name}`} className="input" />
              <p className="blog-field-hint">Falls back to post title. Keep under 60 characters.</p>
            </div>

            <div className="blog-field" style={{ marginTop: 'var(--space-4)' }}>
              <label className="blog-field-label">Meta Description</label>
              <I18nTextarea value={form.meta_description} lang={lang} onChange={val => set('meta_description', val)} placeholder={`SEO description in ${activeLang.name}`} className="textarea" rows={3} />
              <p className="blog-field-hint">Keep under 160 characters.</p>
            </div>

            <div className="blog-field" style={{ marginTop: 'var(--space-4)' }}>
              <label className="blog-field-label">OG Image</label>
              <ImageUpload value={form.og_image} onChange={v => set('og_image', v)} uploadLabel="Upload OG Image" />
              <p className="blog-field-hint">1200×630px recommended. Falls back to cover.</p>
            </div>
          </div>
        </div>

        {/* ── Sidebar ──────────────────────────────────────────────────────── */}
        <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)' }}>

          {/* Basic Info */}
          <div className="card" style={{ padding: 'var(--space-5)' }}>
            <div className="blog-section-label">Basic Info</div>

            <div className="blog-field">
              <label className="blog-field-label">Title (EN)</label>
              <input
                className={`input${errors.titleEn ? ' blog-input--error' : ''}`}
                value={i18nOf(form.title, 'en')}
                onChange={handleEnTitleChange}
                placeholder="English title"
              />
              {errors.titleEn && <p className="blog-field-error">{errors.titleEn}</p>}
            </div>

            <div className="blog-field" style={{ marginTop: 'var(--space-4)' }}>
              <label className="blog-field-label">Slug</label>
              <input
                className={`input${errors.slug ? ' blog-input--error' : ''}`}
                value={form.slug}
                onChange={handleSlugChange}
                placeholder="post-url-slug"
                style={{ fontFamily: 'var(--font-mono, monospace)', fontSize: 13 }}
              />
              {errors.slug
                ? <p className="blog-field-error">{errors.slug}</p>
                : <p className="blog-field-hint">Auto-generated. Editable.</p>
              }
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr auto', gap: 'var(--space-4)', alignItems: 'end', marginTop: 'var(--space-4)' }}>
              <div>
                <label className="blog-field-label">Status</label>
                <select className="input" value={form.status} onChange={e => set('status', e.target.value)}>
                  <option value="draft">Draft</option>
                  <option value="published">Published</option>
                </select>
              </div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, paddingBottom: 2 }}>
                <input
                  type="checkbox"
                  id="featured-toggle"
                  checked={form.featured}
                  onChange={e => set('featured', e.target.checked)}
                  style={{ width: 16, height: 16, cursor: 'pointer' }}
                />
                <label htmlFor="featured-toggle" style={{ fontSize: 'var(--fs-body-sm)', cursor: 'pointer', whiteSpace: 'nowrap' }}>Featured</label>
              </div>
            </div>
          </div>

          {/* Cover & Meta */}
          <div className="card" style={{ padding: 'var(--space-5)' }}>
            <div className="blog-section-label">Cover & Meta</div>

            <div className="blog-field">
              <label className="blog-field-label">Cover Image</label>
              <ImageUpload value={form.cover_url} onChange={v => set('cover_url', v)} uploadLabel="Upload Cover" />
            </div>

            <div className="blog-field" style={{ marginTop: 'var(--space-4)' }}>
              <label className="blog-field-label">Category</label>
              <CategorySelect
                value={form.category}
                onChange={v => set('category', v)}
                categories={categories}
                onCreate={onCreateCategory}
              />
            </div>

            <div className="blog-field" style={{ marginTop: 'var(--space-4)' }}>
              <label className="blog-field-label">Tags</label>
              <TagInput value={form.tags} onChange={v => set('tags', v)} />
            </div>

            <div className="blog-field" style={{ marginTop: 'var(--space-4)' }}>
              <label className="blog-field-label">Reading Time (min)</label>
              <input
                className="input"
                type="number"
                min={1} max={60}
                value={form.reading_time}
                onChange={e => set('reading_time', Number(e.target.value) || 5)}
              />
            </div>
          </div>

        </div>
      </div>
    </div>
  );
}

// ─── Blog page ─────────────────────────────────────────────────────────────────

function Blog() {
  const [posts,      setPosts]      = React.useState([]);
  const [categories, setCategories] = React.useState([]);
  const [loading,    setLoading]    = React.useState(true);
  const [view,       setView]       = React.useState('list');
  const [editing,    setEditing]    = React.useState(null);
  const [saving,     setSaving]     = React.useState(false);
  const [toast,      setToast]      = React.useState(null);
  const [confirm,    setConfirm]    = React.useState(null);

  const showToast = (msg, type = 'success') => {
    setToast({ msg, type });
    setTimeout(() => setToast(null), 3000);
  };

  React.useEffect(() => {
    Promise.all([
      db.from('blog_posts').select('*').order('created_at', { ascending: false }),
      db.from('categories').select('*').order('name'),
    ]).then(([postsRes, catsRes]) => {
      if (!postsRes.error && postsRes.data) setPosts(postsRes.data);
      if (!catsRes.error  && catsRes.data)  setCategories(catsRes.data);
      setLoading(false);
    });
  }, []);

  const handleNew  = () => { setEditing(null); setView('form'); };

  const handleEdit = (post) => {
    setEditing({
      ...post,
      tags:             Array.isArray(post.tags) ? post.tags : [],
      meta_title:       post.meta_title       || i18nBlank(),
      meta_description: post.meta_description || i18nBlank(),
      og_image:         post.og_image         || '',
    });
    setView('form');
  };

  const handleDelete = (post) => setConfirm(post);

  const confirmDelete = async () => {
    const post = confirm;
    setConfirm(null);
    const { error } = await db.from('blog_posts').delete().eq('id', post.id);
    if (error) { showToast('Delete failed: ' + error.message, 'error'); return; }
    setPosts(prev => prev.filter(p => p.id !== post.id));
    showToast('Post deleted');
  };

  const handleToggleFeatured = async (post) => {
    const next = !post.featured;
    const { error } = await db.from('blog_posts').update({ featured: next }).eq('id', post.id);
    if (error) { showToast('Update failed', 'error'); return; }
    setPosts(prev => prev.map(p => p.id === post.id ? { ...p, featured: next } : p));
  };

  const handleCreateCategory = async (name) => {
    const { data, error } = await db.from('categories').insert([{ name }]).select().single();
    if (error) { showToast('Failed to create category', 'error'); return null; }
    setCategories(prev => [...prev, data].sort((a, b) => a.name.localeCompare(b.name)));
    return data.name;
  };

  const handleSave = async (form) => {
    setSaving(true);

    const payload = {
      slug:             form.slug.trim(),
      status:           form.status,
      featured:         form.featured,
      title:            form.title,
      excerpt:          form.excerpt,
      content:          form.content,
      cover_url:        form.cover_url        || null,
      category:         form.category         || null,
      tags:             Array.isArray(form.tags) ? form.tags : [],
      reading_time:     form.reading_time      || 5,
      meta_title:       form.meta_title,
      meta_description: form.meta_description,
      og_image:         form.og_image          || null,
      updated_at:       new Date().toISOString(),
    };

    if (form.status === 'published' && !editing?.published_at) {
      payload.published_at = new Date().toISOString();
    }

    let error, data;

    if (editing) {
      ({ error, data } = await db.from('blog_posts').update(payload).eq('id', editing.id).select().single());
    } else {
      ({ error, data } = await db.from('blog_posts').insert([payload]).select().single());
    }

    setSaving(false);

    if (error) {
      showToast(error.code === '23505' ? 'A post with this slug already exists' : error.message, 'error');
      return;
    }

    if (editing) {
      setPosts(prev => prev.map(p => p.id === data.id ? data : p));
    } else {
      setPosts(prev => [data, ...prev]);
    }

    showToast(form.status === 'published' ? 'Post published' : 'Draft saved');
    setView('list');
    setEditing(null);
  };

  if (loading) {
    return <div style={{ padding: 'var(--space-8)', color: 'var(--fg-secondary)' }}>Loading…</div>;
  }

  return (
    <div>
      <BlogToast toast={toast} />

      {confirm && (
        <DeleteConfirm
          title={i18nOf(confirm.title, 'en') || confirm.slug}
          onConfirm={confirmDelete}
          onCancel={() => setConfirm(null)}
        />
      )}

      {view === 'list' && (
        <BlogList
          posts={posts}
          onNew={handleNew}
          onEdit={handleEdit}
          onDelete={handleDelete}
          onToggleFeatured={handleToggleFeatured}
        />
      )}

      {view === 'form' && (
        <BlogForm
          initial={editing}
          onSave={handleSave}
          onCancel={() => { setView('list'); setEditing(null); }}
          saving={saving}
          categories={categories}
          onCreateCategory={handleCreateCategory}
        />
      )}
    </div>
  );
}
