// HelperMatch Admin — Phase B5: Articles CRUD
// List + rich-ish editor (markdown) + multi-language + publish/schedule/archive

// ============================================================
// Shared bits
// ============================================================
const ART_CATS = ['Taiwan', 'Hong Kong', 'Singapore', 'Platform', 'Hiring', 'Policy', 'Story'];
const ART_LANGS = [
  { key: 'Zh', label: '繁中', flag: '🇹🇼' },
  { key: 'En', label: 'EN',   flag: '🇬🇧' },
  { key: 'Id', label: 'ID',   flag: '🇮🇩' },
];

const slugify = (s) => (s || '')
  .toLowerCase()
  .replace(/[^\w\s-]/g, '')
  .replace(/\s+/g, '-')
  .replace(/-+/g, '-')
  .replace(/^-|-$/g, '')
  .slice(0, 80);

const readingTime = (md) => {
  const words = (md || '').split(/\s+/).filter(Boolean).length;
  const mins = Math.max(1, Math.round(words / 200));
  return mins + ' min read';
};

// Placeholder cover image (seeded color gradient + icon)
const CoverThumb = ({ article, size = 'sm' }) => {
  const w = size === 'lg' ? 220 : size === 'md' ? 120 : 72;
  const h = size === 'lg' ? 132 : size === 'md' ? 72  : 44;
  const hue = ((article.id || 'x').charCodeAt(article.id.length - 1) * 37) % 360;
  const c1 = `oklch(0.62 0.14 ${hue})`;
  const c2 = `oklch(0.46 0.12 ${(hue + 45) % 360})`;
  const icon = article.category === 'Taiwan' ? '🇹🇼' : article.category === 'Hong Kong' ? '🇭🇰' : article.category === 'Singapore' ? '🇸🇬' : article.category === 'Hiring' ? '📝' : article.category === 'Platform' ? '⚙️' : article.category === 'Policy' ? '📜' : '📖';
  return (
    <div style={{
      width: w, height: h, borderRadius: 6, flexShrink: 0,
      background: `linear-gradient(135deg, ${c1}, ${c2})`,
      display:'flex', alignItems:'center', justifyContent:'center',
      fontSize: size === 'lg' ? 38 : size === 'md' ? 22 : 16,
      overflow:'hidden', position:'relative',
    }}>
      <span style={{filter:'drop-shadow(0 1px 3px rgba(0,0,0,.25))'}}>{icon}</span>
    </div>
  );
};

// Article status badge (reuses StatusBadge map when possible)
const ArtStatus = ({ status }) => {
  const M = {
    DRAFT:     { label: '草稿',    bg: 'var(--a-paper-2)',     fg: 'var(--a-ink-soft)', bd: 'var(--a-line)' },
    SCHEDULED: { label: '排程中',  bg: 'oklch(0.96 0.06 270)', fg: 'oklch(0.42 0.15 270)', bd: 'oklch(0.82 0.1 270)' },
    PUBLISHED: { label: '已發佈',  bg: 'oklch(0.96 0.09 155)', fg: 'oklch(0.36 0.15 155)', bd: 'oklch(0.78 0.12 155)' },
    ARCHIVED:  { label: '已封存',  bg: 'var(--a-paper-2)',     fg: 'var(--a-ink-faint)',bd: 'var(--a-line)' },
  };
  const m = M[status] || M.DRAFT;
  return (
    <span style={{
      display:'inline-flex', alignItems:'center', padding:'2px 8px',
      fontSize:11, fontWeight:600, borderRadius:4,
      background:m.bg, color:m.fg, border:'1px solid '+m.bd, letterSpacing:0.3,
    }}>{m.label}</span>
  );
};

// Lang completion pill — which translations exist for an article
const LangPills = ({ art }) => (
  <div style={{display:'flex',gap:3}}>
    {ART_LANGS.map(l => {
      const has = !!art['title' + l.key];
      return (
        <span key={l.key} title={l.label + (has ? ' 已填寫' : ' 未填')} style={{
          width: 22, height: 16, borderRadius: 3, fontSize: 9, fontWeight: 700,
          display:'inline-flex', alignItems:'center', justifyContent:'center',
          background: has ? 'oklch(0.94 0.05 210)' : 'var(--a-paper-2)',
          color:    has ? 'oklch(0.42 0.13 210)' : 'var(--a-ink-faint)',
          border: '1px solid '+(has ? 'oklch(0.82 0.09 210)' : 'var(--a-line)'),
          letterSpacing: 0.3,
        }}>{l.key.toUpperCase()}</span>
      );
    })}
  </div>
);

// ============================================================
// Tiny Markdown renderer (safe-ish)
// Supports: # H1, ## H2, ### H3, **bold**, *italic*, `code`,
// - lists, 1. lists, > quotes, --- hr, [text](url), ![alt](url), paragraphs
// ============================================================
const renderMd = (md) => {
  if (!md) return null;
  const lines = md.replace(/\r/g, '').split('\n');
  const out = [];
  let i = 0;
  const inline = (s) => {
    // escape
    let r = s
      .replace(/&/g, '&amp;')
      .replace(/</g, '&lt;')
      .replace(/>/g, '&gt;');
    r = r.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (m, a, u) => `<img alt="${a}" src="${u}" style="max-width:100%;border-radius:6px;margin:8px 0;"/>`);
    r = r.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (m, a, u) => `<a href="${u}" target="_blank" rel="noreferrer" style="color:var(--a-primary);text-decoration:underline;">${a}</a>`);
    r = r.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
    r = r.replace(/\*([^*]+)\*/g, '<em>$1</em>');
    r = r.replace(/`([^`]+)`/g, '<code style="font-family:var(--a-font-mono);background:var(--a-paper-2);padding:1px 5px;border-radius:3px;font-size:0.9em;">$1</code>');
    return r;
  };
  while (i < lines.length) {
    const ln = lines[i];
    if (!ln.trim()) { i++; continue; }
    if (ln.startsWith('### ')) { out.push(<h3 key={i} style={{fontSize:16,fontWeight:600,margin:'18px 0 8px',color:'var(--a-ink)'}}>{ln.slice(4)}</h3>); i++; continue; }
    if (ln.startsWith('## '))  { out.push(<h2 key={i} style={{fontSize:19,fontWeight:600,margin:'22px 0 10px',color:'var(--a-ink)'}}>{ln.slice(3)}</h2>); i++; continue; }
    if (ln.startsWith('# '))   { out.push(<h1 key={i} style={{fontSize:23,fontWeight:700,margin:'26px 0 12px',color:'var(--a-ink)',lineHeight:1.3}}>{ln.slice(2)}</h1>); i++; continue; }
    if (ln.startsWith('---'))  { out.push(<hr key={i} style={{border:'none',borderTop:'1px solid var(--a-line)',margin:'20px 0'}}/>); i++; continue; }
    if (ln.startsWith('> '))   {
      const qs = [];
      while (i < lines.length && lines[i].startsWith('> ')) { qs.push(lines[i].slice(2)); i++; }
      out.push(<blockquote key={'q'+i} style={{margin:'14px 0',padding:'10px 14px',borderLeft:'3px solid var(--a-primary)',background:'var(--a-paper-2)',color:'var(--a-ink-soft)',fontStyle:'italic',borderRadius:'0 6px 6px 0'}} dangerouslySetInnerHTML={{__html: inline(qs.join(' '))}}/>);
      continue;
    }
    if (/^\s*[-*]\s/.test(ln)) {
      const items = [];
      while (i < lines.length && /^\s*[-*]\s/.test(lines[i])) { items.push(lines[i].replace(/^\s*[-*]\s/, '')); i++; }
      out.push(<ul key={'u'+i} style={{margin:'10px 0 10px 20px',padding:0,color:'var(--a-ink)'}}>{items.map((it,k) => <li key={k} style={{margin:'4px 0'}} dangerouslySetInnerHTML={{__html: inline(it)}}/>)}</ul>);
      continue;
    }
    if (/^\s*\d+\.\s/.test(ln)) {
      const items = [];
      while (i < lines.length && /^\s*\d+\.\s/.test(lines[i])) { items.push(lines[i].replace(/^\s*\d+\.\s/, '')); i++; }
      out.push(<ol key={'o'+i} style={{margin:'10px 0 10px 22px',padding:0,color:'var(--a-ink)'}}>{items.map((it,k) => <li key={k} style={{margin:'4px 0'}} dangerouslySetInnerHTML={{__html: inline(it)}}/>)}</ol>);
      continue;
    }
    // paragraph
    const ps = [];
    while (i < lines.length && lines[i].trim() && !lines[i].startsWith('#') && !lines[i].startsWith('- ') && !lines[i].startsWith('* ') && !lines[i].startsWith('> ') && !lines[i].startsWith('---') && !/^\s*\d+\.\s/.test(lines[i])) {
      ps.push(lines[i]); i++;
    }
    out.push(<p key={'p'+i} style={{margin:'8px 0',lineHeight:1.7,color:'var(--a-ink)'}} dangerouslySetInnerHTML={{__html: inline(ps.join(' '))}}/>);
  }
  return out;
};

// ============================================================
// ARTICLES PAGE
// ============================================================
const ArticlesPageReal = () => {
  const { t } = (window.useI18n ? window.useI18n() : { t: (k)=>k });
  const toast = useToast();
  const [arts, setArts] = uS(() => ADMIN.articles.map(a => ({
    ...a,
    // ensure shape
    status: a.status || 'DRAFT',
    scheduledAt: a.scheduledAt || null,
    updatedAt: a.updatedAt || a.publishedAt || ADMIN.now,
    views: a.views != null ? a.views : Math.floor(((a.id.charCodeAt(a.id.length-1) * 173) % 4800)),
  })));

  const [tab, setTab] = uS(() => {
    const m = window.location.hash.match(/status=([A-Z_]+)/);
    return m ? m[1] : 'ALL';
  });
  const [q, setQ] = uS('');
  const [catFilter, setCatFilter] = uS('');
  const [sortBy, setSortBy] = uS('updated');
  const [openId, setOpenId] = uS(null);
  const [isNew, setIsNew] = uS(false);

  const tabs = [
    { key: 'ALL',       label: '全部' },
    { key: 'DRAFT',     label: '草稿' },
    { key: 'SCHEDULED', label: '排程中' },
    { key: 'PUBLISHED', label: '已發佈' },
    { key: 'ARCHIVED',  label: '已封存' },
  ];
  const tabCount = (k) => k === 'ALL' ? arts.length : arts.filter(a => a.status === k).length;

  const filtered = uM(() => {
    let r = arts;
    if (tab !== 'ALL') r = r.filter(a => a.status === tab);
    if (catFilter) r = r.filter(a => a.category === catFilter);
    if (q) {
      const qL = q.toLowerCase();
      r = r.filter(a =>
        (a.titleZh || '').toLowerCase().includes(qL) ||
        (a.titleEn || '').toLowerCase().includes(qL) ||
        (a.slug    || '').toLowerCase().includes(qL) ||
        a.id.toLowerCase().includes(qL)
      );
    }
    const sorters = {
      updated:   (a,b) => new Date(b.updatedAt) - new Date(a.updatedAt),
      published: (a,b) => new Date(b.publishedAt||0) - new Date(a.publishedAt||0),
      views:     (a,b) => (b.views||0) - (a.views||0),
      title:     (a,b) => (a.titleZh||'').localeCompare(b.titleZh||'','zh-Hant'),
    };
    return [...r].sort(sorters[sortBy]);
  }, [arts, tab, q, catFilter, sortBy]);

  const open = (a) => { setOpenId(a.id); setIsNew(false); };
  const createNew = () => {
    const id = 'art_' + Math.random().toString(36).slice(2,7);
    const fresh = {
      id, slug:'', category: 'Platform', status: 'DRAFT',
      titleZh: '', titleEn: null, titleId: null,
      excerptZh: '', excerptEn: null, excerptId: null,
      contentZh: '# 新標題\n\n在此開始撰寫…', contentEn: null, contentId: null,
      author: 'Vincent Chen', publishedAt: null, scheduledAt: null,
      updatedAt: new Date(),
      views: 0, cover: null,
    };
    setArts([fresh, ...arts]);
    setOpenId(id); setIsNew(true);
  };

  const updateArt = (id, patch) => setArts(list => list.map(a => a.id === id ? {...a, ...patch, updatedAt: new Date()} : a));
  const deleteArt = (id) => { setArts(list => list.filter(a => a.id !== id)); setOpenId(null); };

  const current = arts.find(a => a.id === openId);

  return (
    <div className="a-page a-page-wide">
      <div className="a-page-header">
        <div>
          <h1 className="a-page-title">{t('admin.articles.title')}</h1>
          <p className="a-page-sub">{t('admin.articles.subtitle')}</p>
        </div>
        <div className="a-page-header-actions">
          <button className="a-btn a-btn-default" onClick={()=>window.open('#','_blank')}>
            <AIcon name="external" size={13}/> 預覽站台
          </button>
          <button className="a-btn a-btn-primary" onClick={createNew}>
            <AIcon name="plus" size={13}/> 新建文章
          </button>
        </div>
      </div>

      {/* KPI strip */}
      <div style={{display:'grid', gridTemplateColumns:'repeat(4, 1fr)', gap:12, marginBottom:14}}>
        <KpiMini label="已發佈" value={arts.filter(a=>a.status==='PUBLISHED').length} icon="article" tone="success"/>
        <KpiMini label="草稿" value={arts.filter(a=>a.status==='DRAFT').length} icon="edit" tone="neutral"/>
        <KpiMini label="排程中" value={arts.filter(a=>a.status==='SCHEDULED').length} icon="clock" tone="primary"/>
        <KpiMini label="本月瀏覽" value={arts.reduce((s,a)=>s+(a.views||0),0).toLocaleString()} icon="eye" tone="neutral"/>
      </div>

      <div className="a-card">
        <div className="a-tabs">
          {tabs.map(t => (
            <button key={t.key} className={`a-tab ${tab===t.key ? 'a-tab-active' : ''}`} onClick={()=>setTab(t.key)}>
              {t.label} <span className="a-tab-count">{tabCount(t.key)}</span>
            </button>
          ))}
        </div>

        <div className="a-table-toolbar">
          <div className="a-input-group" style={{width:300}}>
            <span className="a-input-group-prefix"><AIcon name="search" size={14}/></span>
            <input className="a-input" placeholder="搜尋標題 / slug / ID…" value={q} onChange={e=>setQ(e.target.value)}/>
          </div>
          <select className="a-select" style={{width:160}} value={catFilter} onChange={e=>setCatFilter(e.target.value)}>
            <option value="">所有類別</option>
            {ART_CATS.map(c => <option key={c} value={c}>{c}</option>)}
          </select>
          <select className="a-select" style={{width:160}} value={sortBy} onChange={e=>setSortBy(e.target.value)}>
            <option value="updated">最近更新</option>
            <option value="published">最近發佈</option>
            <option value="views">瀏覽量</option>
            <option value="title">標題排序</option>
          </select>
          <span className="ml-auto text-muted fs-13">共 {filtered.length} 筆</span>
        </div>

        {filtered.length === 0 ? (
          <AEmpty icon="article" title="沒有符合條件的文章" sub="試試其他篩選或建立第一篇文章"/>
        ) : (
          <table className="a-table a-table-hover">
            <thead>
              <tr>
                <th style={{width:90}}>封面</th>
                <th>標題</th>
                <th style={{width:120}}>類別</th>
                <th style={{width:100}}>語言</th>
                <th style={{width:110}}>狀態</th>
                <th style={{width:100}}>作者</th>
                <th style={{width:130}}>更新時間</th>
                <th style={{width:100}}>瀏覽</th>
                <th style={{width:40}}></th>
              </tr>
            </thead>
            <tbody>
              {filtered.map(a => (
                <tr key={a.id} onClick={()=>open(a)}>
                  <td><CoverThumb article={a} size="sm"/></td>
                  <td>
                    <div className="fw-600 fs-13" style={{color:'var(--a-ink)', marginBottom:2}}>
                      {a.titleZh || <span className="text-faint">(無標題)</span>}
                    </div>
                    <div className="text-muted fs-12" style={{display:'flex',gap:8,alignItems:'center'}}>
                      <Mono>/{a.slug || '...'}</Mono>
                      <span>·</span>
                      <span>{readingTime(a.contentZh)}</span>
                    </div>
                  </td>
                  <td><span className="a-badge a-badge-neutral">{a.category}</span></td>
                  <td><LangPills art={a}/></td>
                  <td>
                    <ArtStatus status={a.status}/>
                    {a.status === 'SCHEDULED' && a.scheduledAt && (
                      <div className="fs-11 text-muted" style={{marginTop:2}}>{FMT.iso(a.scheduledAt).slice(0,16)}</div>
                    )}
                  </td>
                  <td className="fs-13">{a.author}</td>
                  <td className="fs-12 text-muted">{FMT.rel(a.updatedAt)}</td>
                  <td className="tnum fs-13">{(a.views||0).toLocaleString()}</td>
                  <td><AIcon name="chevRight" size={13} className="text-faint"/></td>
                </tr>
              ))}
            </tbody>
          </table>
        )}
      </div>

      {current && (
        <ArticleEditor
          article={current}
          isNew={isNew}
          allArts={arts}
          onClose={()=>setOpenId(null)}
          onChange={(patch)=>updateArt(current.id, patch)}
          onDelete={()=>deleteArt(current.id)}
          onPublish={()=>{ updateArt(current.id, { status:'PUBLISHED', publishedAt: new Date(), scheduledAt:null }); toast.show('已發佈 — ' + (current.titleZh || current.id), 'success'); setOpenId(null); }}
          onSchedule={(at)=>{ updateArt(current.id, { status:'SCHEDULED', scheduledAt: at, publishedAt:null }); toast.show('已排程於 ' + FMT.iso(at), 'success'); setOpenId(null); }}
          onArchive={()=>{ updateArt(current.id, { status:'ARCHIVED' }); toast.show('已封存', 'info'); setOpenId(null); }}
          onRestore={()=>{ updateArt(current.id, { status:'DRAFT' }); toast.show('已還原為草稿', 'info'); }}
          onSaveDraft={()=>{ toast.show('草稿已儲存', 'success'); }}
        />
      )}
    </div>
  );
};

// ============================================================
// KpiMini
// ============================================================
const KpiMini = ({ label, value, icon, tone='neutral' }) => {
  const tc = tone === 'success' ? 'var(--a-success)' : tone === 'primary' ? 'var(--a-primary)' : tone === 'warn' ? 'var(--a-warn)' : 'var(--a-ink-soft)';
  const bg = tone === 'success' ? 'oklch(0.95 0.06 155)' : tone === 'primary' ? 'var(--a-primary-50)' : tone === 'warn' ? 'oklch(0.96 0.07 80)' : 'var(--a-paper-2)';
  return (
    <div className="a-card" style={{padding:'12px 14px', display:'flex', alignItems:'center', gap:12}}>
      <div style={{width:36,height:36,borderRadius:8,background:bg,color:tc,display:'flex',alignItems:'center',justifyContent:'center'}}>
        <AIcon name={icon} size={16}/>
      </div>
      <div>
        <div className="fs-11 text-muted fw-600" style={{letterSpacing:0.4,textTransform:'uppercase'}}>{label}</div>
        <div style={{fontSize:19,fontWeight:700,color:'var(--a-ink)',lineHeight:1.2}}>{value}</div>
      </div>
    </div>
  );
};

// ============================================================
// ARTICLE EDITOR (drawer, wide)
// ============================================================
const ArticleEditor = ({ article, isNew, allArts, onClose, onChange, onDelete, onPublish, onSchedule, onArchive, onRestore, onSaveDraft }) => {
  const [draft, setDraft] = uS({ ...article });
  const [lang, setLang] = uS('Zh');
  const [mode, setMode] = uS('edit'); // edit | preview
  const [showSchedule, setShowSchedule] = uS(false);
  const [showDelete, setShowDelete] = uS(false);
  const [slugTouched, setSlugTouched] = uS(!!article.slug);

  uE(() => { setDraft({...article}); setSlugTouched(!!article.slug); }, [article.id]);

  const patch = (p) => { const next = {...draft, ...p}; setDraft(next); onChange(p); };

  // Auto-generate slug from zh title until user types one
  uE(() => {
    if (!slugTouched && draft.titleZh && draft.status === 'DRAFT') {
      const next = slugify(draft.titleEn || draft.titleZh);
      if (next !== draft.slug) patch({ slug: next });
    }
  }, [draft.titleZh, draft.titleEn]);

  const titleKey   = 'title' + lang;
  const excerptKey = 'excerpt' + lang;
  const contentKey = 'content' + lang;

  const slugTaken = allArts.some(a => a.id !== draft.id && a.slug && a.slug === draft.slug);
  const wordCount = (draft.contentZh || '').length + (draft.contentEn || '').length + (draft.contentId || '').length;

  const canPublish = !!draft.titleZh && !!draft.slug && !!draft.contentZh && !slugTaken;

  return (
    <ADrawer open={true} onClose={onClose} size="xl" title={
      <div style={{display:'flex',alignItems:'center',gap:10}}>
        <span>{isNew ? '新建文章' : '編輯文章'}</span>
        <ArtStatus status={draft.status}/>
        <Mono>{draft.id}</Mono>
      </div>
    }>
    <div style={{margin:-18}}>
      {/* Top action bar */}
      <div style={{
        display:'flex',alignItems:'center',gap:8,padding:'10px 18px',
        borderBottom:'1px solid var(--a-line)',background:'var(--a-paper-2)',
        position:'sticky',top:0,zIndex:2,
      }}>
        <div style={{display:'flex',gap:4,background:'var(--a-paper)',border:'1px solid var(--a-line)',borderRadius:6,padding:3}}>
          <button onClick={()=>setMode('edit')} className={`a-btn a-btn-sm ${mode==='edit'?'a-btn-primary':'a-btn-ghost'}`} style={{minWidth:60,border:'none'}}>
            <AIcon name="edit" size={12}/> 編輯
          </button>
          <button onClick={()=>setMode('preview')} className={`a-btn a-btn-sm ${mode==='preview'?'a-btn-primary':'a-btn-ghost'}`} style={{minWidth:60,border:'none'}}>
            <AIcon name="eye" size={12}/> 預覽
          </button>
        </div>
        <div style={{display:'flex',gap:4,background:'var(--a-paper)',border:'1px solid var(--a-line)',borderRadius:6,padding:3}}>
          {ART_LANGS.map(l => {
            const has = !!draft['title'+l.key];
            return (
              <button key={l.key} onClick={()=>setLang(l.key)} className={`a-btn a-btn-sm ${lang===l.key?'a-btn-default':'a-btn-ghost'}`} style={{minWidth:62,border:'none',position:'relative'}}>
                <span style={{marginRight:4}}>{l.flag}</span>{l.label}
                {!has && lang!==l.key && (<span style={{position:'absolute',top:3,right:3,width:5,height:5,borderRadius:'50%',background:'var(--a-warn)'}}/>)}
              </button>
            );
          })}
        </div>
        <div style={{marginLeft:'auto',display:'flex',gap:8}}>
          {draft.status === 'ARCHIVED' ? (
            <button className="a-btn a-btn-default" onClick={onRestore}><AIcon name="refresh" size={13}/> 還原為草稿</button>
          ) : (
            <>
              <button className="a-btn a-btn-ghost" onClick={()=>setShowDelete(true)}><AIcon name="trash" size={13}/></button>
              <button className="a-btn a-btn-ghost" onClick={onArchive}><AIcon name="archive" size={13}/> 封存</button>
              <button className="a-btn a-btn-default" onClick={onSaveDraft}><AIcon name="save" size={13}/> 儲存草稿</button>
              <button className="a-btn a-btn-default" onClick={()=>setShowSchedule(true)}><AIcon name="clock" size={13}/> 排程</button>
              <button className="a-btn a-btn-primary" onClick={onPublish} disabled={!canPublish} title={!canPublish ? '需要標題、slug、中文內容' : ''}>
                <AIcon name="check" size={13}/> 發佈
              </button>
            </>
          )}
        </div>
      </div>

      {/* Body: main + meta */}
      <div style={{display:'grid',gridTemplateColumns:'1fr 280px',gap:0}}>
        {/* MAIN */}
        <div style={{padding:'20px 24px', borderRight:'1px solid var(--a-line)', minWidth:0}}>
          {mode === 'edit' ? (
            <EditorBody
              draft={draft}
              lang={lang}
              titleKey={titleKey}
              excerptKey={excerptKey}
              contentKey={contentKey}
              onPatch={patch}
            />
          ) : (
            <PreviewBody draft={draft} lang={lang}/>
          )}
        </div>

        {/* META panel */}
        <div style={{padding:'20px 18px', background:'var(--a-paper-2)'}}>
          <MetaPanel
            draft={draft}
            isNew={isNew}
            slugTaken={slugTaken}
            onPatch={patch}
            onSlugChange={(v)=>{ setSlugTouched(true); patch({slug: v}); }}
          />
        </div>
      </div>
    </div>

      {showSchedule && (
        <ScheduleModal onClose={()=>setShowSchedule(false)} onConfirm={(at)=>{ onSchedule(at); setShowSchedule(false); }}/>
      )}
      {showDelete && (
        <AModal open={true} onClose={()=>setShowDelete(false)} title="刪除文章？" width={420}>
          <div style={{padding:'6px 4px 18px', color:'var(--a-ink-soft)', lineHeight:1.6}}>
            此操作無法復原。此文章與所有語言版本將永久移除。<br/>
            若只是暫時不發佈，可改用「封存」。
          </div>
          <div style={{display:'flex',gap:8,justifyContent:'flex-end'}}>
            <button className="a-btn a-btn-default" onClick={()=>setShowDelete(false)}>取消</button>
            <button className="a-btn a-btn-danger" onClick={()=>{ onDelete(); setShowDelete(false); }}><AIcon name="trash" size={13}/> 確認刪除</button>
          </div>
        </AModal>
      )}
    </ADrawer>
  );
};

// ============================================================
// EDITOR BODY (left pane)
// ============================================================
const EditorBody = ({ draft, lang, titleKey, excerptKey, contentKey, onPatch }) => {
  const txRef = React.useRef(null);

  const wrap = (pfx, sfx = pfx) => {
    const ta = txRef.current; if (!ta) return;
    const s = ta.selectionStart, e = ta.selectionEnd;
    const val = ta.value;
    const sel = val.slice(s, e) || '文字';
    const next = val.slice(0, s) + pfx + sel + sfx + val.slice(e);
    onPatch({ [contentKey]: next });
    setTimeout(() => { ta.focus(); ta.setSelectionRange(s + pfx.length, s + pfx.length + sel.length); }, 0);
  };
  const prefixLine = (p) => {
    const ta = txRef.current; if (!ta) return;
    const s = ta.selectionStart;
    const val = ta.value;
    const before = val.slice(0, s);
    const lineStart = before.lastIndexOf('\n') + 1;
    const next = val.slice(0, lineStart) + p + val.slice(lineStart);
    onPatch({ [contentKey]: next });
    setTimeout(() => { ta.focus(); ta.setSelectionRange(s + p.length, s + p.length); }, 0);
  };

  const tbBtn = (icon, tip, on) => (
    <button type="button" title={tip} onClick={on} style={{
      width:30,height:30,border:'none',background:'transparent',cursor:'pointer',
      color:'var(--a-ink-soft)',borderRadius:4,display:'inline-flex',alignItems:'center',justifyContent:'center',
    }}
      onMouseEnter={e=>e.currentTarget.style.background='var(--a-paper-2)'}
      onMouseLeave={e=>e.currentTarget.style.background='transparent'}
    >
      <AIcon name={icon} size={14}/>
    </button>
  );

  return (
    <div>
      {/* Title */}
      <input
        className="a-input"
        placeholder={lang==='Zh'?'標題…':'Title…'}
        value={draft[titleKey] || ''}
        onChange={e=>onPatch({[titleKey]: e.target.value})}
        style={{
          fontSize:26,fontWeight:700,padding:'6px 0',border:'none',background:'transparent',
          color:'var(--a-ink)',width:'100%',marginBottom:12,letterSpacing:'-0.01em',
        }}
      />

      {/* Excerpt */}
      <textarea
        className="a-input"
        placeholder={lang==='Zh'?'摘要（顯示於列表頁，SEO 用）…':'Excerpt (shown on listings)…'}
        value={draft[excerptKey] || ''}
        onChange={e=>onPatch({[excerptKey]: e.target.value})}
        rows={2}
        style={{
          fontSize:14,padding:'8px 0',border:'none',background:'transparent',
          color:'var(--a-ink-soft)',width:'100%',marginBottom:18,resize:'vertical',lineHeight:1.5,fontFamily:'inherit',
        }}
      />

      <hr style={{border:'none',borderTop:'1px solid var(--a-line)',margin:'0 -24px 0'}}/>

      {/* Toolbar */}
      <div style={{
        display:'flex',alignItems:'center',gap:2,padding:'6px 0',marginBottom:8,
        borderBottom:'1px solid var(--a-line)',marginLeft:-24,marginRight:-24,paddingLeft:24,paddingRight:24,
        background:'var(--a-paper)',position:'sticky',top:0,zIndex:1,
      }}>
        {tbBtn('h1', 'H1 標題', ()=>prefixLine('# '))}
        {tbBtn('h2', 'H2 小標', ()=>prefixLine('## '))}
        {tbBtn('h3', 'H3 段落標', ()=>prefixLine('### '))}
        <span style={{width:1,height:16,background:'var(--a-line)',margin:'0 4px'}}/>
        {tbBtn('bold', '粗體 Ctrl+B', ()=>wrap('**'))}
        {tbBtn('italic', '斜體', ()=>wrap('*'))}
        {tbBtn('code', '行內程式碼', ()=>wrap('`'))}
        <span style={{width:1,height:16,background:'var(--a-line)',margin:'0 4px'}}/>
        {tbBtn('list', '項目列表', ()=>prefixLine('- '))}
        {tbBtn('listNum', '編號列表', ()=>prefixLine('1. '))}
        {tbBtn('quote', '引用區塊', ()=>prefixLine('> '))}
        {tbBtn('hr', '分隔線', ()=>wrap('\n\n---\n\n', ''))}
        <span style={{width:1,height:16,background:'var(--a-line)',margin:'0 4px'}}/>
        {tbBtn('link', '連結 [text](url)', ()=>wrap('[', '](https://)'))}
        {tbBtn('image', '圖片', ()=>wrap('![alt](', 'https://example.com/image.jpg)'))}
        <span style={{marginLeft:'auto',fontSize:11,color:'var(--a-ink-faint)'}}>
          {(draft[contentKey]||'').length} 字 · {readingTime(draft[contentKey])}
        </span>
      </div>

      {/* Content textarea */}
      <textarea
        ref={txRef}
        className="a-input"
        placeholder={lang==='Zh'?'在此撰寫 Markdown 內容…\n\n支援：\n# ## ### 標題\n**粗體**、*斜體*、`code`\n- 項目、1. 編號\n> 引用\n[連結](url)、![圖片](url)':'Write Markdown here…'}
        value={draft[contentKey] || ''}
        onChange={e=>onPatch({[contentKey]: e.target.value})}
        style={{
          fontFamily:'var(--a-font-mono)',fontSize:13,lineHeight:1.75,
          minHeight:'calc(100vh - 340px)',width:'100%',
          border:'1px solid var(--a-line)',borderRadius:6,padding:'14px 16px',
          resize:'vertical',color:'var(--a-ink)',
        }}
      />

      {!draft[contentKey] && lang !== 'Zh' && (
        <div style={{marginTop:12,padding:'10px 14px',background:'var(--a-paper-2)',borderRadius:6,fontSize:12,color:'var(--a-ink-soft)',border:'1px dashed var(--a-line)'}}>
          <AIcon name="info" size={12}/> {ART_LANGS.find(l=>l.key===lang).label} 版本尚未填寫。保留空白會在前台自動 fallback 到繁中版。
        </div>
      )}
    </div>
  );
};

// ============================================================
// PREVIEW BODY
// ============================================================
const PreviewBody = ({ draft, lang }) => {
  const titleKey   = 'title' + lang;
  const excerptKey = 'excerpt' + lang;
  const contentKey = 'content' + lang;

  return (
    <div style={{maxWidth:680, margin:'0 auto', padding:'10px 0 40px'}}>
      <div style={{fontSize:11,fontWeight:600,color:'var(--a-primary)',letterSpacing:0.6,textTransform:'uppercase',marginBottom:10}}>
        {draft.category} · {readingTime(draft[contentKey])}
      </div>
      <h1 style={{fontSize:36,fontWeight:700,lineHeight:1.25,color:'var(--a-ink)',margin:'0 0 14px',letterSpacing:'-0.02em'}}>
        {draft[titleKey] || <span style={{color:'var(--a-ink-faint)'}}>(無標題)</span>}
      </h1>
      {draft[excerptKey] && (
        <p style={{fontSize:17,color:'var(--a-ink-soft)',lineHeight:1.55,margin:'0 0 24px',fontWeight:400}}>
          {draft[excerptKey]}
        </p>
      )}
      <div style={{display:'flex',alignItems:'center',gap:10,paddingBottom:20,marginBottom:28,borderBottom:'1px solid var(--a-line)'}}>
        <div style={{
          width:40,height:40,borderRadius:'50%',background:'var(--a-primary-50)',
          color:'var(--a-primary)',display:'flex',alignItems:'center',justifyContent:'center',
          fontSize:14,fontWeight:600,
        }}>{(draft.author||'?')[0]}</div>
        <div>
          <div className="fw-600 fs-14">{draft.author}</div>
          <div className="fs-12 text-muted">
            {draft.status === 'PUBLISHED' && draft.publishedAt ? FMT.iso(draft.publishedAt).slice(0,10)
              : draft.status === 'SCHEDULED' && draft.scheduledAt ? '將於 ' + FMT.iso(draft.scheduledAt) + ' 發佈'
              : '未發佈 · 草稿'}
          </div>
        </div>
      </div>
      <div style={{fontSize:15,lineHeight:1.8}}>
        {renderMd(draft[contentKey]) || (
          <div style={{padding:'40px 0',textAlign:'center',color:'var(--a-ink-faint)'}}>
            <AIcon name="edit" size={28}/><br/><br/>
            本語言尚未填寫內容
          </div>
        )}
      </div>
    </div>
  );
};

// ============================================================
// META PANEL (right side)
// ============================================================
const MetaPanel = ({ draft, isNew, slugTaken, onPatch, onSlugChange }) => (
  <div style={{display:'flex',flexDirection:'column',gap:18}}>
    <MetaSection title="發佈設定">
      <MetaRow label="狀態"><ArtStatus status={draft.status}/></MetaRow>
      {draft.status === 'PUBLISHED' && draft.publishedAt && (
        <MetaRow label="發佈於"><span className="fs-12">{FMT.iso(draft.publishedAt).slice(0,16)}</span></MetaRow>
      )}
      {draft.status === 'SCHEDULED' && draft.scheduledAt && (
        <MetaRow label="排程於"><span className="fs-12" style={{color:'oklch(0.42 0.15 270)'}}>{FMT.iso(draft.scheduledAt).slice(0,16)}</span></MetaRow>
      )}
      <MetaRow label="作者">
        <select className="a-select" style={{width:'100%',fontSize:12}} value={draft.author} onChange={e=>onPatch({author: e.target.value})}>
          <option>Vincent Chen</option>
          <option>Emma Lin</option>
          <option>Tom Wang</option>
        </select>
      </MetaRow>
      <MetaRow label="類別">
        <select className="a-select" style={{width:'100%',fontSize:12}} value={draft.category} onChange={e=>onPatch({category: e.target.value})}>
          {ART_CATS.map(c => <option key={c} value={c}>{c}</option>)}
        </select>
      </MetaRow>
    </MetaSection>

    <MetaSection title="SEO">
      <div>
        <label className="fs-11 fw-600 text-muted" style={{letterSpacing:0.4,textTransform:'uppercase',marginBottom:4,display:'block'}}>Slug</label>
        <div className="a-input-group">
          <span className="a-input-group-prefix" style={{fontFamily:'var(--a-font-mono)',fontSize:11,color:'var(--a-ink-faint)'}}>/blog/</span>
          <input className="a-input" value={draft.slug} onChange={e=>onSlugChange(slugify(e.target.value))} placeholder="auto-generated" style={{fontFamily:'var(--a-font-mono)',fontSize:12}}/>
        </div>
        {slugTaken && (
          <div className="fs-11" style={{color:'var(--a-danger)',marginTop:4}}>
            <AIcon name="alert" size={10}/> 此 slug 已被使用
          </div>
        )}
      </div>
      <div style={{padding:'10px 12px',background:'var(--a-paper)',border:'1px solid var(--a-line)',borderRadius:6}}>
        <div className="fs-11 fw-600 text-muted mb-4" style={{letterSpacing:0.4,textTransform:'uppercase'}}>搜尋預覽</div>
        <div style={{fontSize:14,color:'#1a0dab',lineHeight:1.3,marginBottom:2,fontWeight:500}}>{draft.titleZh || '(標題)'} — HelperMatch</div>
        <div style={{fontSize:11,color:'#006621',marginBottom:3,fontFamily:'var(--a-font-mono)'}}>helpermatch.com/blog/{draft.slug || '...'}</div>
        <div style={{fontSize:12,color:'#4d5156',lineHeight:1.4}}>
          {draft.excerptZh ? draft.excerptZh.slice(0,155) : '(摘要將顯示於此)'}
        </div>
      </div>
    </MetaSection>

    <MetaSection title="封面圖片">
      {draft.cover ? (
        <div style={{position:'relative'}}>
          <img src={draft.cover} alt="cover" style={{width:'100%',borderRadius:6,display:'block'}}/>
          <button className="a-btn a-btn-sm a-btn-danger" style={{position:'absolute',top:6,right:6}} onClick={()=>onPatch({cover:null})}>
            <AIcon name="x" size={12}/>
          </button>
        </div>
      ) : (
        <div style={{
          border:'1px dashed var(--a-line)',borderRadius:6,padding:'28px 16px',
          textAlign:'center',background:'var(--a-paper)',cursor:'pointer',
        }} onClick={()=>{
          const u = prompt('圖片 URL：', 'https://images.unsplash.com/photo-');
          if (u) onPatch({cover: u});
        }}>
          <AIcon name="image" size={22}/>
          <div className="fs-12 text-muted mt-4">點擊上傳封面圖</div>
          <div className="fs-11 text-faint mt-4">建議 1200×630</div>
        </div>
      )}
    </MetaSection>

    <MetaSection title="統計">
      <MetaRow label="瀏覽量"><span className="fw-600">{(draft.views||0).toLocaleString()}</span></MetaRow>
      <MetaRow label="字數"><span>{(draft.contentZh||'').length + (draft.contentEn||'').length + (draft.contentId||'').length}</span></MetaRow>
      <MetaRow label="閱讀時長"><span>{readingTime(draft.contentZh)}</span></MetaRow>
    </MetaSection>

    {!isNew && (
      <MetaSection title="歷史">
        <MetaRow label="建立於"><span className="fs-12 text-muted">{FMT.rel(draft.publishedAt || draft.updatedAt)}</span></MetaRow>
        <MetaRow label="更新於"><span className="fs-12 text-muted">{FMT.rel(draft.updatedAt)}</span></MetaRow>
        <MetaRow label="ID"><Mono>{draft.id}</Mono></MetaRow>
      </MetaSection>
    )}
  </div>
);

const MetaSection = ({ title, children }) => (
  <div>
    <div className="fs-11 fw-600 text-muted mb-8" style={{letterSpacing:0.6,textTransform:'uppercase'}}>{title}</div>
    <div style={{display:'flex',flexDirection:'column',gap:10}}>{children}</div>
  </div>
);
const MetaRow = ({ label, children }) => (
  <div style={{display:'flex',flexDirection:'column',gap:4}}>
    <span className="fs-11 text-muted fw-600" style={{letterSpacing:0.3}}>{label}</span>
    {children}
  </div>
);

// ============================================================
// SCHEDULE MODAL
// ============================================================
const ScheduleModal = ({ onClose, onConfirm }) => {
  const tomorrow = new Date(Date.now() + 86400000);
  tomorrow.setHours(9, 0, 0, 0);
  const [dateStr, setDateStr] = uS(() => tomorrow.toISOString().slice(0,10));
  const [timeStr, setTimeStr] = uS('09:00');

  const scheduledAt = new Date(dateStr + 'T' + timeStr + ':00');
  const inPast = scheduledAt.getTime() <= Date.now();

  return (
    <AModal open={true} onClose={onClose} title="排程發佈" width={460}>
      <div style={{padding:'4px 0 14px'}}>
        <p className="text-muted fs-13 mb-14" style={{lineHeight:1.6}}>
          文章會在指定時間自動發佈。設定後狀態改為「排程中」，在發佈前可取消或修改。
        </p>
        <div style={{display:'grid',gridTemplateColumns:'1fr 1fr',gap:12}}>
          <div>
            <label className="fs-11 fw-600 text-muted mb-4" style={{display:'block',letterSpacing:0.3,textTransform:'uppercase'}}>日期</label>
            <input type="date" className="a-input" value={dateStr} onChange={e=>setDateStr(e.target.value)} min={new Date().toISOString().slice(0,10)}/>
          </div>
          <div>
            <label className="fs-11 fw-600 text-muted mb-4" style={{display:'block',letterSpacing:0.3,textTransform:'uppercase'}}>時間</label>
            <input type="time" className="a-input" value={timeStr} onChange={e=>setTimeStr(e.target.value)}/>
          </div>
        </div>
        <div style={{marginTop:12, padding:'10px 12px', background:'var(--a-paper-2)', borderRadius:6, fontSize:12, color:'var(--a-ink-soft)'}}>
          <AIcon name="clock" size={11}/> 排定於 <span className="fw-600" style={{color:'var(--a-ink)'}}>{FMT.iso(scheduledAt).slice(0,16)}</span>
          {!inPast && <span style={{marginLeft:6,color:'var(--a-ink-faint)'}}>（{Math.ceil((scheduledAt - Date.now())/3600000)} 小時後）</span>}
        </div>
        {inPast && <div className="fs-12" style={{color:'var(--a-danger)',marginTop:8}}><AIcon name="alert" size={11}/> 時間必須在未來</div>}
      </div>
      <div style={{display:'flex',gap:8,justifyContent:'flex-end'}}>
        <button className="a-btn a-btn-default" onClick={onClose}>取消</button>
        <button className="a-btn a-btn-primary" onClick={()=>onConfirm(scheduledAt)} disabled={inPast}>
          <AIcon name="check" size={13}/> 確認排程
        </button>
      </div>
    </AModal>
  );
};

// ============================================================
// Export
// ============================================================
Object.assign(window, {
  ArticlesPageReal, CoverThumb, ArtStatus, LangPills, renderMd,
});
