/* TokensPage.jsx — three-pane token workspace (tree · list · drawer) */
const { useState: useStateTP, useMemo: useMemoTP } = React;

/* ---- brand theme dropdown ---- */
function ThemeMenu({ theme, setTheme, drop = 'down', full = false, onManage }) {
  const [open, setOpen] = useStateTP(false);
  return (
    <div className={cx('relative', full && 'w-full')}>
      <button onClick={() => setOpen((o) => !o)}
      className={cx('h-8 flex items-center gap-2 pl-2 pr-2.5 bg-panel border border-line rounded-[8px] text-[13px] text-ink hover:bg-hover transition focus-ring', full && 'w-full')}>
        <span className="w-[18px] h-[18px] rounded-[4px] flex items-center justify-center text-white text-[10px] font-semibold border border-line2 shrink-0 overflow-hidden" style={{ background: theme.accent[500] }}>{theme.logo ? <img src={theme.logo} alt="" className="w-full h-full object-cover" /> : (theme.name||'?').trim().charAt(0).toUpperCase()}</span>
        <span className="font-medium truncate">{theme.name}</span>
        <Icon name="chevronD" size={13} className="text-ink3 ml-auto shrink-0" />
      </button>
      {open &&
      <>
          <div className="fixed inset-0 z-10" onClick={() => setOpen(false)} />
          <div className={cx('absolute z-20 w-60 bg-panel border border-line rounded-[12px] py-1.5 shadow-[0_8px_28px_rgba(0,0,0,0.18)]',
        drop === 'up' ? 'bottom-[40px]' : 'top-9', full ? 'left-0' : 'right-0')} style={{ animation: 'fadeIn 120ms ease' }}>
            <div className="px-3 py-1 text-[10.5px] uppercase tracking-wide text-ink3">Brand theme</div>
            {THEMES.map((th) =>
          <button key={th.id} onClick={() => {setTheme(th);setOpen(false);}}
          className={cx('w-full flex items-center gap-2.5 px-3 h-10 text-left hover:bg-hover transition', th.id === theme.id && 'bg-accentWeak')}>
                <span className="w-7 h-7 rounded-[7px] flex items-center justify-center text-white text-[12px] font-semibold border border-line2 shrink-0 overflow-hidden" style={{ background: th.accent[500] }}>
                  {th.logo ? <img src={th.logo} alt="" className="w-full h-full object-cover" /> : (th.name || '?').trim().charAt(0).toUpperCase()}
                </span>
                <span className="flex-1 min-w-0">
                  <span className="block text-[13px] text-ink font-medium leading-tight">{th.name}</span>
                  <span className="block text-[11px] text-ink3 leading-tight">{th.line}</span>
                </span>
                {th.id === theme.id && <Icon name="check" size={15} className="text-accent" />}
              </button>
          )}
            {onManage &&
          <>
                <div className="border-t border-line my-1" />
                <button onClick={() => {onManage();setOpen(false);}}
            className="w-full flex items-center gap-2 px-3 h-9 text-left text-[12.5px] text-ink2 hover:text-ink hover:bg-hover transition">
                  <Icon name="sliders" size={14} className="text-ink3 shrink-0" />
                  <span className="flex-1">{tr('Manage themes','全部主题')}</span>
                  <Icon name="chevronR" size={13} className="text-ink3 shrink-0" />
                </button>
              </>
          }
          </div>
        </>
      }
    </div>);

}

/* ---- filter dropdown ---- */
/* Filtering now uses the shared <FilterMenu> primitive from ui.jsx; the per-page
   group config is built at render (so tr() stays language-reactive) — see tokenFilterGroups(). */
function tokenFilterGroups() {
  return [
    { key: 'layer',  label: tr('Layer','层级'),  opts: [['all', tr('All','全部')], ['primitive', tr('Primitive','原始')], ['semantic', tr('Semantic','语义')], ['component', tr('Component','组件')]] },
    { key: 'kind',   label: tr('Type','类型'),   opts: [['all', tr('All','全部')], ['color', tr('Color','颜色')], ['spacing', tr('Spacing','间距')], ['type', tr('Typography','字体')], ['radius', tr('Radius','圆角')], ['shadow', tr('Shadow','阴影')]] },
    { key: 'status', label: tr('Status','状态'), opts: [['all', tr('All','全部')], ['new', tr('New','新增')], ['modified', tr('Modified','修改')], ['deprecated', tr('Deprecated','废弃')]] },
  ];
}

/* ---- tree ---- */
function TokenTree({ scope, setScope, rev }) {
  const [openLayers, setOpenLayers] = useStateTP({ primitive: true, semantic: true, component: true });
  const counts = useMemoTP(() => {
    const m = {};
    TOKENS.forEach((t) => {
      const lk = t.layer,ck = t.layer + '/' + t.category;
      m[lk] = m[lk] || { n: 0, d: 0 };m[ck] = m[ck] || { n: 0, d: 0 };
      m[lk].n++;m[ck].n++;
      const dirty = t.status === 'new' || t.status === 'modified' || t.status === 'renamed';
      if (dirty) {m[lk].d++;m[ck].d++;}
    });
    return m;
  }, [rev]);

  return (
    <div className="w-[226px] shrink-0 border-r border-line bg-panel overflow-y-auto ds-scroll py-2">
      <button onClick={() => setScope(null)}
      className={cx('w-full flex items-center gap-2 px-4 h-8 text-[13px] transition', !scope ? 'text-accent font-medium' : 'text-ink2 hover:text-ink')}>
        <Icon name="layers" size={14} />All tokens
        <span className="ml-auto text-[11px] text-ink3">{TOKENS.length}</span>
      </button>
      <div className="h-px bg-line mx-4 my-2" />
      {LAYERS.map((layer) => {
        const cats = CATEGORIES.filter((c) => TOKENS.some((t) => t.layer === layer.id && t.category === c));
        const lc = counts[layer.id] || { n: 0, d: 0 };
        const isOpen = openLayers[layer.id];
        return (
          <div key={layer.id} className="mb-0.5">
            <button onClick={() => setOpenLayers((o) => ({ ...o, [layer.id]: !o[layer.id] }))}
            className="w-full flex items-center gap-1.5 px-3 h-8 text-ink hover:bg-hover rounded-[4px] transition group">
              <Icon name={isOpen ? 'chevronD' : 'chevronR'} size={13} className="text-ink3" />
              <span className="text-[12.5px] font-semibold">{layer.name}</span>
              {lc.d > 0 && <span className="w-1.5 h-1.5 rounded-full bg-accent" />}
              <span className="ml-auto text-[11px] text-ink3 font-mono">{lc.n}</span>
            </button>
            {isOpen &&
            <div className="pb-1">
                {cats.map((cat) => {
                const cc = counts[layer.id + '/' + cat] || { n: 0, d: 0 };
                const sel = scope && scope.layer === layer.id && scope.category === cat;
                return (
                  <button key={cat} onClick={() => setScope({ layer: layer.id, category: cat })}
                  className={cx('w-full flex items-center gap-2 pl-8 pr-3 h-[30px] text-[12.5px] rounded-[4px] transition',
                  sel ? 'bg-accentWeak text-accent font-medium' : 'text-ink2 hover:text-ink hover:bg-hover')}>
                      {cat}
                      {cc.d > 0 && <span className="w-1.5 h-1.5 rounded-full bg-accent" />}
                      <span className="ml-auto text-[11px] text-ink3 font-mono">{cc.n}</span>
                    </button>);

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

      })}
    </div>);

}

/* ---- list row ---- */
function TokenRow({ token, ctx, selected, onClick }) {
  const r = resolve(token.id, ctx);
  const tgt = nextRef(token.source, ctx.mode);
  const deprecated = token.status === 'deprecated';
  const deps = dependentsOf(token.id);
  const depComp = deps.filter(id => TOKEN_MAP[id] && TOKEN_MAP[id].layer === 'component').length;
  return (
    <button onClick={onClick}
    className={cx('w-full grid items-center gap-3 px-4 py-2 min-h-[52px] text-left border-b border-[color:var(--border)] transition-colors group',
    selected ? 'bg-accentWeak' : 'hover:bg-hover', deprecated && 'opacity-55')}
    style={{ gridTemplateColumns: '28px minmax(0,1.5fr) minmax(0,1fr) 92px 84px' }}>
      <span className="flex justify-center self-start mt-0.5"><KindPreview token={token} ctx={ctx} size={24} /></span>
      <span className="min-w-0 flex flex-col justify-center gap-0.5">
        <span className="flex items-center gap-1.5">
          <StatusDot status={token.status} />
          <span className={cx('font-mono text-[13px] truncate', deprecated ? 'text-ink2 line-through' : 'text-ink')}>{token.id}</span>
        </span>
        {token.description
          ? <span className="text-[11.5px] text-ink2 leading-snug line-clamp-1">{token.description}</span>
          : <span className="text-[11.5px] text-ink3 italic">No description</span>}
      </span>
      <span className="min-w-0 flex flex-col justify-center gap-0.5">
        <span className="font-mono text-[12.5px] text-ink2 truncate">{fmtRowValue(token, r)}</span>
        {tgt && <RefChain chain={r.chain} size={11} />}
      </span>
      <span className="flex justify-start">
        {deps.length > 0
          ? <span title={deps.length + ' references' + (depComp ? ' · ' + depComp + ' components' : '')}
              className="inline-flex items-center gap-1 h-[20px] pl-1.5 pr-2 rounded-[4px] bg-sunken border border-line text-[11px] text-ink2 group-hover:border-line2 transition">
              <Icon name="link" size={11} className="text-ink3" />
              <span className="font-mono tabular-nums">{deps.length}</span>
            </span>
          : <span className="text-[11px] text-ink3 pl-1.5">—</span>}
      </span>
      <span className="flex justify-end self-center">{deprecated ? <StatusTag status="deprecated" /> : token.status !== 'published' ? <StatusTag status={token.status} /> : <Icon name="chevronR" size={14} className="text-ink3 opacity-0 group-hover:opacity-100 transition" />}</span>
    </button>);

}
function fmtRowValue(token, r) {
  if (r.cycle) return '⚠ cycle';
  if (token.kind === 'color') return r.value;
  if (token.kind === 'spacing' || token.kind === 'radius') return r.value + 'px';
  if (token.kind === 'type') return r.value + ' / ' + (r.lh || '—') + ' px';
  if (token.kind === 'shadow') return r.value;
  return String(r.value);
}

/* ---- loading skeleton ---- */
function ListSkeleton() {
  return <div>{Array.from({ length: 8 }).map((_, i) =>
    <div key={i} className="grid items-center gap-3 px-4 min-h-[52px] py-2 border-b border-[color:var(--border)]" style={{ gridTemplateColumns: '28px minmax(0,1.5fr) minmax(0,1fr) 92px 84px' }}>
      <span className="skel w-6 h-6 rounded-[4px]" />
      <span className="flex flex-col gap-1.5"><span className="skel h-3 rounded w-40" /><span className="skel h-2.5 rounded w-28" /></span>
      <span className="skel h-3 rounded w-24" />
      <span className="skel h-4 rounded-[4px] w-10" />
      <span className="skel h-3 rounded w-12 justify-self-end" />
      <span className="skel h-3 rounded w-12 justify-self-end" />
    </div>
    )}</div>;
}

/* ---- Design-tokens DOC editor (Drawer) ----
   Manager-facing editor for the front-end "Design tokens" doc page. Upload/replace
   the Usage / Content (naming) / Design markdown via processMdFiles (same pattern as
   the component "Replace .md"); writes the language-correct field on TOKEN_DOC in
   memory. The changelog is read-only — derived from CHANGE_HISTORY (token items). */
function tokenDocChangelog() {
  const hist = (typeof CHANGE_HISTORY !== 'undefined') ? CHANGE_HISTORY : [];
  return hist
    .map(rel => ({ rel, items: (rel.items || []).filter(it => it.kind === 'token') }))
    .filter(g => g.items.length);
}
function TokenDocDrawer({ open, onClose }) {
  const zh = getAppLang() === 'zh';
  const [, force] = useStateTP(0);
  const doc = (typeof TOKEN_DOC !== 'undefined') ? TOKEN_DOC : null;
  if (!open || !doc) return null;
  const bump = () => force(r => r + 1);

  const SECTIONS = [
    { key: 'usage',   base: 'usageMd',   zhf: 'usageMdZh',   title: tr('Usage', '用法'),     hint: tr('How to use tokens — semantic over primitive, search by purpose, theming.', '如何使用 token —— 用语义而非原始、按用途搜索、换肤。') },
    { key: 'content', base: 'contentMd', zhf: 'contentMdZh', title: tr('Content', '文案'),   hint: tr('The token naming rules — grammar, separators, scale convention.', 'Token 命名规范 —— 语法、分隔符、刻度约定。') },
    { key: 'design',  base: 'designMd',  zhf: 'designMdZh',  title: tr('Design', '设计思路'), hint: tr('Design rationale — why three tiers, why themeAccent.', '设计思路 —— 为何三层、为何 themeAccent。') },
  ];
  const field = (s) => zh ? s.zhf : s.base;
  const onMd = async (s, e) => {
    const md = await processMdFiles(e.target.files); e.target.value = '';
    if (md != null) { doc[field(s)] = md; bump(); }
  };
  const clear = (s) => { doc[field(s)] = ''; bump(); };

  const releases = tokenDocChangelog();

  return (
    <Drawer open={open} onClose={onClose} width={560}>
      <div className="flex items-start justify-between px-5 pt-4 pb-3 border-b border-line shrink-0">
        <div className="min-w-0">
          <div className="text-[11px] uppercase tracking-wide text-ink3 mb-1">{tr('Foundation', '基础')} · {tr('Design tokens', '设计 Token')}</div>
          <h2 className="text-[16px] font-semibold text-ink">{tr('Doc', '文档')}</h2>
        </div>
        <IconButton name="close" title={tr('Close', '关闭')} onClick={onClose} />
      </div>
      <div className="flex-1 overflow-y-auto ds-scroll px-5 py-5 flex flex-col gap-6">
        <p className="text-[12.5px] text-ink2 leading-relaxed">
          {tr('This is the documentation shown on the public “Design tokens” page (Examples · Usage · Content · Design · Changelog). The Examples and Changelog tabs are generated automatically; the three markdown sections below are editable here.',
              '这是公开「设计 Token」页(示例 · 用法 · 文案 · 设计思路 · 更新日志)所展示的文档。示例与更新日志自动生成;下方三段 Markdown 可在此编辑。')}
        </p>

        {/* language note */}
        <div className="rounded-[10px] border border-line bg-sunken px-3 py-2 text-[12px] text-ink2 inline-flex items-center gap-2">
          <Icon name="edit" size={13} className="text-ink3" />
          {tr('Uploads write the', '上传将写入')} <b className="text-ink">{zh ? '中文' : 'EN'}</b> {tr('version (switch language in the top bar to edit the other).', '版本(在顶部切换语言以编辑另一种)。')}
        </div>

        {SECTIONS.map(s => {
          const val = doc[field(s)];
          return (
            <div key={s.key}>
              <div className="flex items-center gap-2 mb-1.5">
                <h3 className="text-[13.5px] font-semibold text-ink">{s.title}</h3>
                <span className="text-[11px] text-ink3 font-mono">{field(s)}</span>
              </div>
              <p className="text-[12px] text-ink3 mb-2.5 leading-snug">{s.hint}</p>
              <div className="flex items-center gap-3 mb-2.5">
                <label className={cx('inline-flex items-center gap-1.5 h-8 px-3 rounded-[8px] text-[13px] font-medium border border-line cursor-pointer hover:bg-hover transition', !canEdit() && 'opacity-40 pointer-events-none')}>
                  <Icon name="upload" size={15} />{tr('Upload .md + images', '上传 .md + 图片')}
                  <input type="file" accept=".md,.markdown,image/*,video/*,.pdf,.doc,.docx,.ppt,.pptx" multiple className="hidden" onChange={(e) => onMd(s, e)} />
                </label>
                {val && canEdit() && <button onClick={() => clear(s)} className="text-[12.5px] text-ink3 hover:text-danger transition">{tr('Clear', '清除')}</button>}
              </div>
              {val
                ? <div className="rounded-[12px] border border-line bg-sunken p-4 max-h-[300px] overflow-y-auto ds-scroll"><MarkdownDoc md={val} /></div>
                : <div className="rounded-[12px] border border-dashed border-line2 bg-sunken p-6 text-center text-[12.5px] text-ink3">{tr('No content yet. Select your .md file together with any images it references.', '暂无内容。选择你的 .md 文件以及它引用的图片一起上传。')}</div>}
            </div>
          );
        })}

        {/* auto-generated changelog (read-only) */}
        <div>
          <div className="flex items-center gap-2 mb-1.5">
            <h3 className="text-[13.5px] font-semibold text-ink">{tr('Changelog', '更新日志')}</h3>
            <span className="inline-flex items-center gap-1 text-[11px] text-ink3"><Icon name="diff" size={11} />{tr('Automatic', '自动')}</span>
          </div>
          <p className="text-[12px] text-ink3 mb-2.5 leading-snug">{tr('Derived from shipped releases — token changes only. Not editable.', '从已发布版本中提取 —— 仅含 token 变更,不可编辑。')}</p>
          {releases.length === 0
            ? <div className="rounded-[12px] border border-dashed border-line2 bg-sunken p-6 text-center text-[12.5px] text-ink3">{tr('No token changes recorded yet.', '暂无 token 变更记录。')}</div>
            : <div className="rounded-[12px] border border-line bg-sunken p-4 flex flex-col gap-3">
                {releases.map(({ rel, items }) => (
                  <div key={rel.id} className="flex gap-3">
                    <div className="w-16 shrink-0"><span className="font-mono text-[12px] text-ink">#{rel.number}</span><div className="text-[10.5px] text-ink3">{rel.date}</div></div>
                    <ul className="flex-1 border-l border-line pl-3 flex flex-col gap-1">
                      {items.map(it => {
                        const m = (ACTION_META && ACTION_META[it.action]) || { label: it.action, color: 'var(--text-2)' };
                        return (
                          <li key={it.id} className="text-[12px] leading-snug flex items-start gap-1.5">
                            <span className="inline-flex items-center h-[16px] px-1.5 rounded-[4px] text-[10px] font-medium shrink-0 mt-px" style={{ background: 'color-mix(in srgb, ' + m.color + ' 13%, transparent)', color: m.color }}>{m.label}</span>
                            <span className="font-mono text-ink2 truncate">{it.target}</span>
                          </li>
                        );
                      })}
                    </ul>
                  </div>
                ))}
              </div>}
        </div>
      </div>
      <div className="shrink-0 border-t border-line px-5 py-3 flex justify-end bg-panel">
        <Button variant="secondary" onClick={onClose}>{tr('Done', '完成')}</Button>
      </div>
    </Drawer>
  );
}

/* ---- page ---- */
function TokensPage({ ctx, mode, setMode, theme, setTheme, onOpenToken, onNewToken, onImport, selectedId, rev }) {
  const [docOpen, setDocOpen] = useStateTP(false);
  const [scope, setScope] = useStateTP(null);
  const [q, setQ] = useStateTP('');
  const [filters, setFilters] = useStateTP({ kind: 'all', layer: 'all', status: 'all' });
  const [loading, setLoading] = useStateTP(true);
  React.useEffect(() => {const t = setTimeout(() => setLoading(false), 600);return () => clearTimeout(t);}, []);

  const filtered = useMemoTP(() => {
    return TOKENS.filter((t) => {
      if (scope && (t.layer !== scope.layer || t.category !== scope.category)) return false;
      if (filters.layer !== 'all' && t.layer !== filters.layer) return false;
      if (filters.kind !== 'all' && t.kind !== filters.kind) return false;
      if (filters.status !== 'all') {
        if (filters.status === 'modified' && !(t.status === 'modified' || t.status === 'renamed')) return false;
        if (filters.status !== 'modified' && t.status !== filters.status) return false;
      }
      if (q) {
        const qq = q.toLowerCase().replace(/^#/, '');
        const r = resolve(t.id, ctx);
        const hay = [t.id, t.description, t.tags.join(' '), String(r.value || ''), (t.source && t.source.ref) || '', (t.source && t.source.light) || '', (t.source && t.source.dark) || ''].join(' ').toLowerCase();
        if (!hay.includes(qq)) return false;
      }
      return true;
    });
  }, [scope, filters, q, rev, ctx]);

  const grouped = useMemoTP(() => {
    const g = {};
    filtered.forEach((t) => {const k = t.layer + ' · ' + t.category;(g[k] = g[k] || []).push(t);});
    return g;
  }, [filtered]);

  return (
    <div className="flex h-full min-h-0">
      <TokenTree scope={scope} setScope={setScope} rev={rev} />

      <div className="flex-1 min-w-0 flex flex-col">
        {/* toolbar — unified PageToolbar (Tokens keeps its left TokenTree as the category control) */}
        <PageToolbar
          title={tr('Tokens','Token')}
          count={filtered.length}
          titleMeta={scope ? scope.layer + ' · ' + scope.category : tr('All layers','全部层级')}
          contextHint={
            <span className="inline-flex items-center gap-1.5 text-[12px] text-ink3">
              <span className="w-4 h-4 rounded-[4px] flex items-center justify-center text-white text-[9px] font-semibold border border-line2 shrink-0 overflow-hidden" style={{ background: theme.accent[500] }}>{theme.logo ? <img src={theme.logo} alt="" className="w-full h-full object-cover" /> : (theme.name||'?').trim().charAt(0).toUpperCase()}</span>
              {tr('Previewing','预览')} <b className="font-medium text-ink2">{theme.name}</b> · {mode}
            </span>
          }
          leadingActions={<>
            <Button variant="primary" size="sm" icon="plus" disabled={!canEdit()} onClick={onNewToken}>{tr('New','新建')}</Button>
            <Button variant="secondary" size="sm" icon="layers" onClick={() => setDocOpen(true)}>{tr('Doc','文档')}</Button>
            <ImportExportMenu tokens={TOKENS} ctx={ctx} onImport={onImport} />
          </>}
          search={{ value:q, onChange:setQ, placeholder:tr('Search name, #hex, description, tags…','搜索名称、#色值、描述、标签…') }}
          filters={{ groups:tokenFilterGroups(), value:filters, onChange:setFilters }}
        />

        {/* list */}
        <div className="flex-1 overflow-y-auto ds-scroll bg-panel">
          {loading ? <ListSkeleton /> : filtered.length === 0 ?
          <EmptyState icon="search" title="No tokens match" body="Try clearing filters or adjusting your search."
          action={<Button variant="secondary" onClick={() => {setQ('');setFilters({ kind: 'all', layer: 'all', status: 'all' });setScope(null);}}>Reset view</Button>} /> :

          Object.entries(grouped).map(([group, items]) =>
          <div key={group}>
                <div className="sticky top-0 z-[1] flex items-center gap-2 px-4 h-8 bg-sunken/95 backdrop-blur border-b border-line">
                  <span className="text-[11px] font-semibold uppercase tracking-wide text-ink2">{group}</span>
                  <span className="text-[11px] text-ink3 font-mono">{items.length}</span>
                </div>
                {items.map((t) =>
            <TokenRow key={t.id} token={t} ctx={ctx} selected={selectedId === t.id} onClick={() => onOpenToken(t)} />
            )}
              </div>
          )
          }
        </div>
      </div>
      <TokenDocDrawer open={docOpen} onClose={() => setDocOpen(false)} />
    </div>);

}

Object.assign(window, { TokensPage, ThemeMenu, TokenDocDrawer });