// ════════════════════════════════════════════════════════════════
// Admin atoms — переиспользуемые мелочи для всех админ-экранов
// RoleBadge, StatusDot, TokenDisplay, ProgressBar, AdminQuickBar,
// PageHeader, EmptyState, ConfirmRow
// ════════════════════════════════════════════════════════════════

// ── 1. RoleBadge ────────────────────────────────────────────────
function RoleBadge({ role, size = 'md' }) {
  const cfg = window.SDH_ADMIN.ROLES.find(r => r.id === role);
  if (!cfg) return null;
  const sm = size === 'sm';
  const styles = {
    display: 'inline-flex',
    alignItems: 'center',
    gap: sm ? 4 : 6,
    padding: sm ? '2px 7px' : '3px 9px',
    borderRadius: 'var(--radius-full)',
    fontSize: sm ? 10.5 : 11.5,
    fontWeight: role === 'super_admin' ? 600 : 500,
    background: cfg.hue === 'bronze' ? 'var(--brand-bronze-subtle)' : `var(--hue-${cfg.hue}-subtle)`,
    color: cfg.hue === 'bronze' ? 'var(--brand-bronze-deep)' : `var(--hue-${cfg.hue})`,
    border: `1px solid ${cfg.hue === 'bronze' ? 'var(--brand-bronze)' : `var(--hue-${cfg.hue})`}`,
    whiteSpace: 'nowrap',
    lineHeight: 1.3,
  };
  return (
    <span style={styles}>
      <span style={{
        fontFamily: role === 'super_admin' ? 'var(--font-display)' : 'var(--font-mono)',
        fontStyle: role === 'super_admin' ? 'italic' : 'normal',
        fontSize: sm ? 11 : 12,
        lineHeight: 1,
      }}>{cfg.marker}</span>
      <span style={role === 'super_admin' ? {
        fontFamily: 'var(--font-display)', fontStyle: 'italic',
      } : null}>{cfg.label}</span>
    </span>
  );
}

// ── 2. StatusDot ────────────────────────────────────────────────
function StatusDot({ status, label }) {
  const map = {
    active:   { hue: 'emerald', text: label || 'активен' },
    invited:  { hue: 'amber',   text: label || 'приглашён' },
    pending:  { hue: 'amber',   text: label || 'ожидает' },
    expired:  { hue: 'rose',    text: label || 'истёк' },
    revoked:  { hue: 'info',    text: label || 'отозван' },
    accepted: { hue: 'emerald', text: label || 'принято' },
    running:  { hue: 'emerald', text: label || 'работает' },
    idle:     { hue: 'info',    text: label || 'простой' },
    success:  { hue: 'emerald', text: label || 'успех' },
    failed:   { hue: 'rose',    text: label || 'ошибка' },
    pulse:    { hue: 'emerald', text: label || 'live', pulse: true },
  };
  const c = map[status] || map.idle;
  return (
    <span style={{
      display: 'inline-flex', alignItems: 'center', gap: 5,
      fontSize: 12, color: 'var(--text-secondary)',
    }}>
      <span style={{
        width: 7, height: 7, borderRadius: '50%',
        background: `var(--hue-${c.hue})`,
        boxShadow: c.pulse ? `0 0 0 2px var(--hue-${c.hue}-subtle)` : 'none',
        animation: c.pulse ? 'sdhPulse 1.8s ease-in-out infinite' : 'none',
        flexShrink: 0,
      }} />
      <span>{c.text}</span>
    </span>
  );
}

// ── 3. TokenDisplay ─────────────────────────────────────────────
function TokenDisplay({ value, label = 'Bearer token' }) {
  const [copied, setCopied] = React.useState(false);
  const [revealed, setRevealed] = React.useState(false);
  function copy() {
    if (navigator.clipboard) navigator.clipboard.writeText(value).catch(() => {});
    setCopied(true);
    setTimeout(() => setCopied(false), 1600);
  }
  const masked = value.slice(0, 4) + '·'.repeat(Math.max(0, value.length - 8)) + value.slice(-4);
  return (
    <div style={{
      padding: 'var(--space-4)',
      background: 'var(--brand-bronze-subtle)',
      border: '1px solid var(--brand-bronze)',
      borderRadius: 'var(--radius-md)',
    }}>
      <div className="sdh-mono-label" style={{ marginBottom: 4, color: 'var(--brand-bronze-deep)' }}>{label}</div>
      <div style={{
        display: 'flex', alignItems: 'center', gap: 8,
        background: 'var(--surface-elevated)',
        border: '1px solid var(--border-default)',
        borderRadius: 'var(--radius-sm)',
        padding: '8px 10px',
        marginBottom: 'var(--space-3)',
      }}>
        <code style={{
          flex: 1, fontFamily: 'var(--font-mono)', fontSize: 13,
          color: 'var(--text-primary)', overflow: 'auto', whiteSpace: 'nowrap',
        }}>{revealed ? value : masked}</code>
        <button className="sdh-btn sdh-btn--ghost" style={{ padding: '4px 8px', fontSize: 11 }}
          onClick={() => setRevealed(v => !v)}>
          {revealed ? 'скрыть' : 'показать'}
        </button>
        <button className="sdh-btn" style={{ padding: '4px 10px', fontSize: 11 }} onClick={copy}>
          {copied ? '✓ скопировано' : 'копировать'}
        </button>
      </div>
      <div style={{
        fontFamily: 'var(--font-serif-body)', fontStyle: 'italic',
        fontSize: 12.5, color: 'var(--brand-bronze-deep)', lineHeight: 1.45,
      }}>
        Сохраните токен в менеджер паролей. Увидеть снова не получится. При утере нужно регенерировать новый и обновить во всех клиентах.
      </div>
    </div>
  );
}

// ── 4. UsageBar — прогресс с цветом по % ────────────────────────
function UsageBar({ used, total, height = 10, showLabel = true }) {
  const pct = total > 0 ? Math.min(1, used / total) : 0;
  const hue = pct < 0.75 ? 'emerald' : pct < 0.9 ? 'amber' : 'rose';
  return (
    <div>
      {showLabel && (
        <div style={{
          display: 'flex', justifyContent: 'space-between', alignItems: 'baseline',
          marginBottom: 4,
          fontFamily: 'var(--font-mono)', fontSize: 12,
        }}>
          <span style={{ color: 'var(--text-primary)' }}>
            {used.toLocaleString('ru-RU')} <span style={{ color: 'var(--text-tertiary)' }}>/ {total.toLocaleString('ru-RU')}</span>
          </span>
          <span style={{ color: `var(--hue-${hue})`, fontWeight: 600 }}>
            {Math.round(pct * 100)}%
          </span>
        </div>
      )}
      <div style={{
        height, background: 'var(--surface-sunken)',
        border: '1px solid var(--border-subtle)',
        borderRadius: height / 2, overflow: 'hidden',
      }}>
        <div style={{
          width: `${pct * 100}%`, height: '100%',
          background: `var(--hue-${hue})`,
          opacity: 0.85,
          transition: 'width .5s var(--ease-card)',
        }} />
      </div>
    </div>
  );
}

// ── 5. PageHeader — единый паттерн админ-экранов ────────────────
function PageHeader({ section, title, accent, subtitle, right }) {
  const renderTitle = () => {
    if (!accent) return title;
    const parts = title.split(accent);
    if (parts.length === 1) return title;
    return (
      <React.Fragment>
        {parts[0]}
        <em style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic', color: 'var(--brand-bronze-deep)', fontWeight: 600 }}>
          {accent}
        </em>
        {parts[1]}
      </React.Fragment>
    );
  };
  return (
    <section className="sdh-container" style={{ paddingTop: 'var(--space-12)', paddingBottom: 'var(--space-6)' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-end', gap: 'var(--space-6)', flexWrap: 'wrap' }}>
        <div style={{ flex: 1, minWidth: 300 }}>
          <span className="sdh-section-label">{section}</span>
          <h1 className="sdh-hero-h" style={{ marginBottom: subtitle ? 'var(--space-3)' : 0 }}>
            {renderTitle()}
          </h1>
          {subtitle && (
            <p className="sdh-quote" style={{ maxWidth: 720, margin: 0 }}>{subtitle}</p>
          )}
        </div>
        {right && <div style={{ flexShrink: 0 }}>{right}</div>}
      </div>
    </section>
  );
}

// ── 6. EmptyState ───────────────────────────────────────────────
function EmptyState({ title, hint, action }) {
  return (
    <div style={{
      padding: 'var(--space-12) var(--space-8)',
      textAlign: 'center',
      border: '1px dashed var(--border-default)',
      borderRadius: 'var(--radius-xl)',
      background: 'var(--surface-elevated)',
    }}>
      <h3 style={{
        margin: 0, fontFamily: 'var(--font-display)', fontStyle: 'italic',
        fontSize: 20, fontWeight: 500, color: 'var(--text-primary)',
      }}>{title}</h3>
      {hint && <p className="sdh-quote" style={{ margin: 'var(--space-2) auto 0', maxWidth: 460 }}>{hint}</p>}
      {action && <div style={{ marginTop: 'var(--space-4)' }}>{action}</div>}
    </div>
  );
}

// ── 7. AccessDenied — заглушка вместо страницы под чужой ролью ──
function AccessDenied({ requiredRole, currentRole, onBack }) {
  return (
    <div className="sdh-fade">
      <section className="sdh-container" style={{ paddingTop: 'var(--space-16)', paddingBottom: 'var(--space-16)' }}>
        <span className="sdh-section-label">доступ ограничен</span>
        <h1 className="sdh-hero-h" style={{ marginBottom: 'var(--space-3)' }}>
          Этот <em>раздел</em> закрыт
        </h1>
        <p className="sdh-quote" style={{ maxWidth: 580, margin: '0 0 var(--space-6)' }}>
          Ваша роль — <RoleBadge role={currentRole} size="sm" />. Для доступа нужна роль <RoleBadge role={requiredRole} size="sm" /> или выше. Если вам нужен расширенный доступ, обратитесь к super-admin'у через профиль.
        </p>
        {onBack && (
          <button className="sdh-btn" onClick={onBack}>
            <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.5">
              <path d="M7.5 2 4 6l3.5 4" strokeLinecap="round" strokeLinejoin="round" />
            </svg>
            Вернуться в Реестр
          </button>
        )}
      </section>
    </div>
  );
}

// ── 8. AdminQuickBar — pill-кнопки админу в Header ──────────────
function AdminQuickBar({ role, route, onRoute, level = 'full' }) {
  if (role !== 'super_admin' && role !== 'admin') return null;
  const D = window.SDH_DATA;
  const A = window.SDH_ADMIN;
  const B = window.SDH_BILLING;

  const pendingInvites = A.invites.filter(i => i.status === 'pending').length;
  const expiringTokens = A.users.filter(u => u.token_warning).length;
  const cronOn = A.pipeline.cron_enabled && !A.pipeline.running ? 'idle' : A.pipeline.running ? 'running' : 'idle';
  const monthCostUsd = B.adminSummary().monthCostUsd;
  const newReqs = role === 'super_admin' ? B.adminSummary().newReqsCount : 0;
  const totalBadge = pendingInvites + expiringTokens + newReqs;

  // Icon-only mode (narrow viewport): single Админка pill with combined badge
  if (level === 'icon') {
    const active = route.startsWith('admin');
    return (
      <div style={{
        display: 'flex', alignItems: 'center', gap: 4,
        paddingLeft: 'var(--space-2)', marginLeft: 'var(--space-2)',
        borderLeft: '1px solid var(--border-subtle)',
        flexShrink: 0,
      }}>
        <button onClick={() => onRoute('admin')}
          className="sdh-btn sdh-btn--ghost"
          style={{
            padding: '5px 8px', fontSize: 12,
            color: active ? 'var(--brand-bronze-deep)' : 'var(--text-secondary)',
            background: active ? 'var(--brand-bronze-subtle)' : 'transparent',
            border: active ? '1px solid var(--brand-bronze)' : '1px solid transparent',
            fontWeight: active ? 600 : 500,
            position: 'relative', whiteSpace: 'nowrap',
            display: 'inline-flex', alignItems: 'center', gap: 5,
          }}
          title="Админ-панель">
          <svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="1.4">
            <rect x="2" y="2" width="5" height="5" rx="1" />
            <rect x="9" y="2" width="5" height="5" rx="1" />
            <rect x="2" y="9" width="5" height="5" rx="1" />
            <rect x="9" y="9" width="5" height="5" rx="1" />
          </svg>
          {totalBadge > 0 && (
            <span style={{
              minWidth: 16, height: 16, padding: '0 4px',
              background: 'var(--brand-bronze)', color: '#fff',
              borderRadius: 8, fontSize: 10, fontWeight: 700, fontFamily: 'var(--font-mono)',
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            }}>{totalBadge}</span>
          )}
        </button>
      </div>
    );
  }

  const compact = level === 'compact';

  const items = compact
    ? [
        { id: 'admin', label: 'Админка', active: route.startsWith('admin'), badge: totalBadge || null },
        role === 'super_admin' && newReqs > 0 ? { id: 'admin.billing', label: 'Биллинг', active: route === 'admin.billing', badge: newReqs } : null,
      ].filter(Boolean)
    : [
        { id: 'admin',         label: 'Админка',  active: route.startsWith('admin'), badge: (pendingInvites + expiringTokens) || null },
        { id: 'admin.users',   label: 'Пользователи', active: route === 'admin.users', count: A.users.filter(u => u.status === 'active').length },
        { id: 'admin.pipeline',label: 'Pipeline', active: route === 'admin.pipeline', status: cronOn },
        role === 'super_admin' && { id: 'admin.cost', label: `$${monthCostUsd.toFixed(2)}`, active: route === 'admin.cost' },
        role === 'super_admin' && newReqs > 0 ? { id: 'admin.billing', label: 'Биллинг', active: route === 'admin.billing', badge: newReqs } : null,
      ].filter(Boolean);

  return (
    <div style={{
      display: 'flex', alignItems: 'center', gap: 4,
      paddingLeft: 'var(--space-3)', marginLeft: 'var(--space-3)',
      borderLeft: '1px solid var(--border-subtle)',
      flexShrink: 0,
    }}>
      {items.map(it => (
        <button key={it.id} onClick={() => onRoute(it.id)}
          className="sdh-btn sdh-btn--ghost"
          style={{
            padding: compact ? '5px 8px' : '5px 10px',
            fontSize: 12,
            color: it.active ? 'var(--brand-bronze-deep)' : 'var(--text-secondary)',
            background: it.active ? 'var(--brand-bronze-subtle)' : 'transparent',
            border: it.active ? '1px solid var(--brand-bronze)' : '1px solid transparent',
            fontWeight: it.active ? 600 : 500,
            position: 'relative',
            whiteSpace: 'nowrap',
            display: 'inline-flex', alignItems: 'center', gap: 5,
          }}>
          {it.status && (
            <span style={{
              width: 6, height: 6, borderRadius: '50%',
              background: it.status === 'running' ? 'var(--success)' : 'var(--text-tertiary)',
            }} />
          )}
          {it.label}
          {typeof it.count === 'number' && (
            <span style={{
              fontFamily: 'var(--font-mono)', fontSize: 10,
              color: 'var(--text-tertiary)', marginLeft: 1,
            }}>{it.count}</span>
          )}
          {it.badge && (
            <span style={{
              minWidth: 16, height: 16, padding: '0 4px',
              background: 'var(--brand-bronze)', color: '#fff',
              borderRadius: 8, fontSize: 10, fontWeight: 700, fontFamily: 'var(--font-mono)',
              display: 'inline-flex', alignItems: 'center', justifyContent: 'center',
            }}>{it.badge}</span>
          )}
        </button>
      ))}
    </div>
  );
}

// ── 9. UserAvatar — кружок с инициалами ─────────────────────────
function UserAvatar({ name, role, size = 32 }) {
  const initials = (name || '?')
    .split(/\s+/).slice(0, 2)
    .map(w => w.charAt(0).toUpperCase()).join('');
  const cfg = window.SDH_ADMIN.ROLES.find(r => r.id === role) || { hue: 'info' };
  const hueVar = cfg.hue === 'bronze' ? 'var(--brand-bronze)' : `var(--hue-${cfg.hue})`;
  const subVar = cfg.hue === 'bronze' ? 'var(--brand-bronze-subtle)' : `var(--hue-${cfg.hue}-subtle)`;
  return (
    <div style={{
      width: size, height: size, borderRadius: '50%',
      background: subVar,
      border: `1px solid ${hueVar}`,
      color: hueVar,
      fontFamily: 'var(--font-mono)', fontSize: size * 0.36, fontWeight: 600,
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      flexShrink: 0,
    }}>{initials}</div>
  );
}

// ── 10. KbdHint — подсказки клавиш ──────────────────────────────
function KbdHint({ keys, label }) {
  return (
    <span className="sdh-mono-label" style={{ marginBottom: 0, display: 'inline-flex', alignItems: 'center', gap: 5 }}>
      {keys.map((k, i) => (
        <React.Fragment key={k}>
          {i > 0 && <span style={{ color: 'var(--text-tertiary)' }}>+</span>}
          <span className="sdh-kbd">{k}</span>
        </React.Fragment>
      ))}
      <span style={{ marginLeft: 4 }}>{label}</span>
    </span>
  );
}

// ── Exports ─────────────────────────────────────────────────────
Object.assign(window, {
  RoleBadge, StatusDot, TokenDisplay, UsageBar, PageHeader,
  EmptyState, AccessDenied, AdminQuickBar, UserAvatar, KbdHint,
});
