/* global React */
// Atomic components + icons.

// ─── Icons (Lucide-style 1.5px stroke, inline) ──────────────────────
function Ic({ d, size = 16, fill, className, style }) {
  return (
    <svg width={size} height={size} viewBox="0 0 24 24"
         fill={fill || "none"} stroke="currentColor" strokeWidth="1.5"
         strokeLinecap="round" strokeLinejoin="round"
         className={className} style={style}
         dangerouslySetInnerHTML={{ __html: d }}/>
  );
}
const I = {
  search:    (p) => <Ic {...p} d='<circle cx="11" cy="11" r="7"/><path d="m20 20-3.5-3.5"/>' />,
  bell:      (p) => <Ic {...p} d='<path d="M6 8a6 6 0 1 1 12 0c0 7 3 7 3 9H3c0-2 3-2 3-9z"/><path d="M10 21a2 2 0 0 0 4 0"/>' />,
  home:      (p) => <Ic {...p} d='<path d="m3 11 9-8 9 8"/><path d="M5 9v11h14V9"/>' />,
  inbox:     (p) => <Ic {...p} d='<path d="M22 12h-6l-2 3h-4l-2-3H2"/><path d="M5.45 5.1 2 12v7a1 1 0 0 0 1 1h18a1 1 0 0 0 1-1v-7l-3.45-6.9A2 2 0 0 0 16.76 4H7.24a2 2 0 0 0-1.79 1.1z"/>' />,
  database:  (p) => <Ic {...p} d='<ellipse cx="12" cy="5" rx="9" ry="3"/><path d="M3 5v6c0 1.7 4 3 9 3s9-1.3 9-3V5"/><path d="M3 11v6c0 1.7 4 3 9 3s9-1.3 9-3v-6"/>' />,
  book:      (p) => <Ic {...p} d='<path d="M4 19.5A2.5 2.5 0 0 1 6.5 17H20"/><path d="M6.5 2H20v20H6.5A2.5 2.5 0 0 1 4 19.5v-15A2.5 2.5 0 0 1 6.5 2z"/>' />,
  refresh:   (p) => <Ic {...p} d='<path d="M3 12a9 9 0 1 0 3-6.7L3 8"/><path d="M3 3v5h5"/>' />,
  grid:      (p) => <Ic {...p} d='<rect x="3" y="3" width="7" height="7" rx="1"/><rect x="14" y="3" width="7" height="7" rx="1"/><rect x="3" y="14" width="7" height="7" rx="1"/><rect x="14" y="14" width="7" height="7" rx="1"/>' />,
  message:   (p) => <Ic {...p} d='<path d="M21 11.5a8.4 8.4 0 0 1-.9 3.8 8.5 8.5 0 0 1-7.6 4.7 8.4 8.4 0 0 1-3.8-.9L3 21l1.9-5.7a8.5 8.5 0 0 1 4.6-11.4 8.4 8.4 0 0 1 3.8-.9h.5a8.5 8.5 0 0 1 8 8v.5z"/>' />,
  activity:  (p) => <Ic {...p} d='<path d="M22 12h-4l-3 9L9 3l-3 9H2"/>' />,
  list:      (p) => <Ic {...p} d='<line x1="8" y1="6" x2="21" y2="6"/><line x1="8" y1="12" x2="21" y2="12"/><line x1="8" y1="18" x2="21" y2="18"/><line x1="3" y1="6" x2="3.01" y2="6"/><line x1="3" y1="12" x2="3.01" y2="12"/><line x1="3" y1="18" x2="3.01" y2="18"/>' />,
  settings:  (p) => <Ic {...p} d='<circle cx="12" cy="12" r="3"/><path d="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 1 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 1 1-4 0v-.09a1.65 1.65 0 0 0-1-1.51 1.65 1.65 0 0 0-1.82.33l-.06.06a2 2 0 1 1-2.83-2.83l.06-.06a1.65 1.65 0 0 0 .33-1.82 1.65 1.65 0 0 0-1.51-1H3a2 2 0 1 1 0-4h.09a1.65 1.65 0 0 0 1.51-1 1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 1 1 2.83-2.83l.06.06a1.65 1.65 0 0 0 1.82.33h0a1.65 1.65 0 0 0 1-1.51V3a2 2 0 1 1 4 0v.09a1.65 1.65 0 0 0 1 1.51h0a1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 1 1 2.83 2.83l-.06.06a1.65 1.65 0 0 0-.33 1.82v0a1.65 1.65 0 0 0 1.51 1H21a2 2 0 1 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/>' />,
  check:     (p) => <Ic {...p} d='<polyline points="20 6 9 17 4 12"/>' />,
  x:         (p) => <Ic {...p} d='<line x1="18" y1="6" x2="6" y2="18"/><line x1="6" y1="6" x2="18" y2="18"/>' />,
  plus:      (p) => <Ic {...p} d='<line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/>' />,
  chevR:     (p) => <Ic {...p} d='<polyline points="9 18 15 12 9 6"/>' />,
  chevD:     (p) => <Ic {...p} d='<polyline points="6 9 12 15 18 9"/>' />,
  chevL:     (p) => <Ic {...p} d='<polyline points="15 18 9 12 15 6"/>' />,
  eye:       (p) => <Ic {...p} d='<path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7-11-7-11-7z"/><circle cx="12" cy="12" r="3"/>' />,
  edit:      (p) => <Ic {...p} d='<path d="M11 4H4a2 2 0 0 0-2 2v14a2 2 0 0 0 2 2h14a2 2 0 0 0 2-2v-7"/><path d="M18.5 2.5a2.121 2.121 0 0 1 3 3L12 15l-4 1 1-4 9.5-9.5z"/>' />,
  trash:     (p) => <Ic {...p} d='<polyline points="3 6 5 6 21 6"/><path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"/>' />,
  upload:    (p) => <Ic {...p} d='<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="17 8 12 3 7 8"/><line x1="12" y1="3" x2="12" y2="15"/>' />,
  download:  (p) => <Ic {...p} d='<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"/><polyline points="7 10 12 15 17 10"/><line x1="12" y1="15" x2="12" y2="3"/>' />,
  filter:    (p) => <Ic {...p} d='<polygon points="22 3 2 3 10 12.46 10 19 14 21 14 12.46 22 3"/>' />,
  alert:     (p) => <Ic {...p} d='<path d="M10.29 3.86 1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/>' />,
  info:      (p) => <Ic {...p} d='<circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/>' />,
  play:      (p) => <Ic {...p} d='<polygon points="5 3 19 12 5 21 5 3"/>' />,
  pause:     (p) => <Ic {...p} d='<rect x="6" y="4" width="4" height="16"/><rect x="14" y="4" width="4" height="16"/>' />,
  clock:     (p) => <Ic {...p} d='<circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/>' />,
  layers:    (p) => <Ic {...p} d='<polygon points="12 2 2 7 12 12 22 7 12 2"/><polyline points="2 17 12 22 22 17"/><polyline points="2 12 12 17 22 12"/>' />,
  shield:    (p) => <Ic {...p} d='<path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/>' />,
  cmd:       (p) => <Ic {...p} d='<path d="M18 3a3 3 0 0 0-3 3v12a3 3 0 0 0 3 3 3 3 0 0 0 3-3 3 3 0 0 0-3-3H6a3 3 0 0 0-3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3V6a3 3 0 0 0-3-3 3 3 0 0 0-3 3 3 3 0 0 0 3 3h12a3 3 0 0 0 3-3 3 3 0 0 0-3-3z"/>' />,
  bookOpen:  (p) => <Ic {...p} d='<path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"/><path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"/>' />,
  cloud:     (p) => <Ic {...p} d='<path d="M17.5 19a4.5 4.5 0 1 0 0-9c-.4 0-.8 0-1.2.1A6 6 0 0 0 5 12.3 4 4 0 0 0 6 20h11.5z"/>' />,
  user:      (p) => <Ic {...p} d='<path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>' />,
  arrowR:    (p) => <Ic {...p} d='<line x1="5" y1="12" x2="19" y2="12"/><polyline points="12 5 19 12 12 19"/>' />,
  panel:     (p) => <Ic {...p} d='<rect x="3" y="3" width="18" height="18" rx="2"/><line x1="9" y1="3" x2="9" y2="21"/>' />,
};

// ─── Logo / Brand mark ─────────────────────────────────────────────
function Logo({ size = 28 }) {
  // Stylized Pokéball half-mark, kept simple
  return (
    <svg width={size} height={size} viewBox="0 0 32 32">
      <defs>
        <clipPath id="bm-clip"><rect width="32" height="32" rx="8"/></clipPath>
      </defs>
      <g clipPath="url(#bm-clip)">
        <rect width="32" height="32" fill="var(--indigo)"/>
        <rect y="16" width="32" height="16" fill="var(--surface)"/>
        <rect y="14" width="32" height="4" fill="var(--text)"/>
        <circle cx="16" cy="16" r="4" fill="var(--surface)" stroke="var(--text)" strokeWidth="2"/>
        <circle cx="16" cy="16" r="1.5" fill="var(--text)"/>
      </g>
    </svg>
  );
}

// ─── TypeChip ──────────────────────────────────────────────────────
function TypeChip({ type }) {
  const color = (window.MOCK.TYPE_COLORS)[type] || 'var(--text-3)';
  return <span className="type-chip" style={{ background: color }}>{type}</span>;
}

// ─── Sprite ────────────────────────────────────────────────────────
function Sprite({ name, color = '#ddd', size = 'md', missing = false, label }) {
  const cls = `sprite ${size === 'sm' ? 'sm' : size === 'lg' ? 'lg' : ''} ${missing ? 'missing' : ''}`;
  if (missing) {
    return (
      <div className={cls} title={name}>
        <I.alert size={size === 'sm' ? 12 : 18}/>
      </div>
    );
  }
  // Generate a pixelated "monster" silhouette deterministically from name
  const seed = (name || '').split('').reduce((a, c) => a + c.charCodeAt(0), 0);
  const cells = [];
  for (let y = 0; y < 8; y++) {
    for (let x = 0; x < 8; x++) {
      const v = ((seed * 9301 + (y * 8 + x) * 49297) % 233280) / 233280;
      // Symmetrize horizontally
      const mx = x < 4 ? x : 7 - x;
      const vv = ((seed * 9301 + (y * 8 + mx) * 49297) % 233280) / 233280;
      // Bias: top-rows lower fill, middle higher
      const bias = y < 1 || y > 6 ? .3 : .65;
      if (vv < bias) cells.push([x, y]);
    }
  }
  return (
    <div className={cls} title={label || name} style={{ background: 'transparent', borderColor: 'var(--border)' }}>
      <svg viewBox="0 0 8 8" className="sprite-svg" shapeRendering="crispEdges">
        <rect width="8" height="8" fill={hexAlpha(color, .14)}/>
        {cells.map(([x, y], i) => (
          <rect key={i} x={x} y={y} width="1" height="1" fill={color}/>
        ))}
      </svg>
    </div>
  );
}

function hexAlpha(hex, a) {
  // Accept #RRGGBB
  const h = hex.replace('#','');
  const r = parseInt(h.substring(0,2),16);
  const g = parseInt(h.substring(2,4),16);
  const b = parseInt(h.substring(4,6),16);
  return `rgba(${r},${g},${b},${a})`;
}

// ─── Pill / Badge / Button shortcuts ───────────────────────────────
function Pill({ status, children }) {
  const labels = { pending: '待审', approved: '已通过', rejected: '已驳回', merged: '已合并', new: '新' };
  return <span className={`pill ${status}`}><span className="dot"/>{children || labels[status]}</span>;
}

function Btn({ children, kind = '', size = '', icon, onClick, disabled, title, type='button' }) {
  return (
    <button type={type} onClick={onClick} disabled={disabled} title={title}
            className={`btn ${kind} ${size}`.trim()}>
      {icon}{children}
    </button>
  );
}

function KBD({ children }) { return <span className="kbd">{children}</span>; }

// ─── Toast ─────────────────────────────────────────────────────────
function useToast() {
  const [items, setItems] = React.useState([]);
  const push = React.useCallback((msg, kind = 'ok') => {
    const id = Math.random().toString(36).slice(2);
    setItems((s) => [...s, { id, msg, kind }]);
    setTimeout(() => setItems((s) => s.filter((x) => x.id !== id)), 2600);
  }, []);
  const node = (
    <div className="toast-stack">
      {items.map((t) => (
        <div key={t.id} className="toast">
          <span className="toast-icon">
            {t.kind === 'ok' ? <I.check size={14}/> : t.kind === 'err' ? <I.alert size={14}/> : <I.info size={14}/>}
          </span>
          <span>{t.msg}</span>
        </div>
      ))}
    </div>
  );
  return { push, node };
}

// ─── Empty / Loading ───────────────────────────────────────────────
function Empty({ title, hint, action }) {
  return (
    <div className="empty">
      <div className="glyph"><I.inbox size={26}/></div>
      <div style={{ fontWeight: 500, color: 'var(--text)', marginBottom: 4 }}>{title}</div>
      {hint && <div style={{ fontSize: 13 }}>{hint}</div>}
      {action && <div style={{ marginTop: 16 }}>{action}</div>}
    </div>
  );
}

// ─── Confirm dialog ────────────────────────────────────────────────
function ConfirmDialog({ open, title, body, confirmText='确认', danger, onConfirm, onCancel }) {
  if (!open) return null;
  return (
    <div className="drawer-backdrop" onClick={onCancel} style={{ display:'grid', placeItems:'center' }}>
      <div onClick={(e)=>e.stopPropagation()} className="card" style={{ width:420, animation:'pop .14s ease' }}>
        <div className="card-pad">
          <div style={{ fontWeight: 600, fontSize: 15, marginBottom: 8 }}>{title}</div>
          <div className="muted" style={{ fontSize: 13 }}>{body}</div>
        </div>
        <div className="card-pad" style={{ paddingTop: 0, display:'flex', gap: 8, justifyContent:'flex-end' }}>
          <Btn onClick={onCancel}>取消</Btn>
          <Btn kind={danger ? 'primary' : 'primary'} onClick={onConfirm}>{confirmText}</Btn>
        </div>
      </div>
    </div>
  );
}

// ─── Roles / Permissions ───────────────────────────────────────────
const ROLES = {
  'super-admin': { label: '主管理员', color: '#6366F1', short: '主' },
  'editor':      { label: '编辑',     color: '#10B981', short: '编' },
  'reviewer':    { label: '审核员',   color: '#F59E0B', short: '审' },
};

// What each role can DO on each module.
// 'r' = read, 'w' = write, '' = locked
const PERMS = {
  'super-admin': { dashboard:'w', submissions:'w', data:'w', wiki:'w', scrape:'w', pokedex:'w', feedback:'w', status:'w', audit:'w', settings:'w' },
  'editor':      { dashboard:'r', submissions:'w', data:'w', wiki:'w', scrape:'r', pokedex:'w', feedback:'w', status:'r', audit:'r', settings:'r' },
  'reviewer':    { dashboard:'r', submissions:'w', data:'',  wiki:'r', scrape:'',  pokedex:'r', feedback:'r', status:'',  audit:'r', settings:'r' },
};

function can(role, mod, op = 'r') {
  const p = PERMS[role]?.[mod];
  if (!p) return false;
  if (op === 'r') return p === 'r' || p === 'w';
  if (op === 'w') return p === 'w';
  return false;
}

function RolePill({ role }) {
  const r = ROLES[role] || ROLES['super-admin'];
  return (
    <span style={{
      display:'inline-flex', alignItems:'center', gap: 4,
      padding: '1px 7px', height: 18,
      fontSize: 10, fontWeight: 500,
      background: hexAlpha(r.color, .12), color: r.color,
      border: '1px solid ' + hexAlpha(r.color, .25),
      borderRadius: 'var(--r-pill)',
      whiteSpace: 'nowrap',
    }}>{r.label}</span>
  );
}

function RoleDot({ role, size = 8 }) {
  const r = ROLES[role] || ROLES['super-admin'];
  return <span style={{
    display:'inline-block', width: size, height: size,
    borderRadius: '50%', background: r.color,
    boxShadow: `0 0 0 2px ${hexAlpha(r.color, .2)}`,
  }}/>;
}

// Export to global scope
Object.assign(window, {
  I, Logo, TypeChip, Sprite, Pill, Btn, KBD, useToast, Empty, ConfirmDialog, hexAlpha,
  ROLES, PERMS, can, RolePill, RoleDot,
});
