/* Админка: продукты, версии, лицензии, пользователи, журнал выдач.
   Формы и удаление подключены к реальному API (window.PortalData.admin).
   После мутации вызывается reload() — App перезагружает данные и перерисовывает. */
(function () {
  const { Button, Input, Tag } = window.DesignSystem_219642;
  const D = window.PortalData;
  const { StatusBadge, PageHeading } = window;
  const Select = window.ThemedSelect; // тёмный селект вместо нативного <select>
  const ThemedDate = window.ThemedDate; // тёмный календарь вместо нативного type="date"

  const cellHead = { textAlign: 'left', padding: '12px 18px', fontSize: '11px', letterSpacing: '0.08em', textTransform: 'uppercase', color: 'var(--text-muted)', fontWeight: 600, whiteSpace: 'nowrap' };
  const cell = { padding: '13px 18px', fontSize: '13.5px', color: 'var(--text-secondary)', verticalAlign: 'middle' };

  function TableShell({ head, children }) {
    return (
      <div style={{ background: 'var(--surface-card)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', overflow: 'hidden' }}>
        <table style={{ width: '100%', borderCollapse: 'collapse' }}>
          <thead><tr style={{ background: 'var(--surface-overlay)' }}>{head.map((h, i) => <th key={i} style={cellHead}>{h}</th>)}</tr></thead>
          <tbody>{children}</tbody>
        </table>
      </div>
    );
  }
  function Row({ children }) {
    const [h, setH] = React.useState(false);
    return <tr onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)} style={{ borderTop: '1px solid var(--border)', background: h ? 'var(--surface-card-hover)' : 'transparent', transition: 'background var(--transition)' }}>{children}</tr>;
  }
  function Empty({ cols, text }) {
    return <tr><td colSpan={cols} style={{ ...cell, textAlign: 'center', color: 'var(--text-muted)', padding: '28px 18px' }}>{text}</td></tr>;
  }
  function Mono({ children }) { return <span style={{ fontFamily: 'var(--font-mono)', fontSize: '12.5px' }}>{children}</span>; }
  function IconBtn({ icon, title, onClick, danger }) {
    const [h, setH] = React.useState(false);
    return (
      <button title={title} onClick={onClick} onMouseEnter={() => setH(true)} onMouseLeave={() => setH(false)}
        style={{ background: 'transparent', border: '1px solid', borderColor: h && danger ? 'rgba(239,68,68,0.4)' : 'var(--border)', color: h && danger ? 'var(--red-500)' : 'var(--text-secondary)', width: '30px', height: '30px', borderRadius: 'var(--radius)', cursor: 'pointer', marginLeft: '6px', transition: 'all var(--transition)' }}>
        <i className={icon} style={{ fontSize: '12px' }} />
      </button>
    );
  }

  // ---- Slide-over (форма) ----
  function Drawer({ open, title, onClose, children, onSubmit, submitLabel, busy, error }) {
    if (!open) return null;
    // Портал в body: экраны (.portal-screen) имеют transform от анимации входа,
    // который создаёт containing block и «ловит» position:fixed. Портал выносит
    // модальное окно в body, чтобы центрирование шло относительно всего окна.
    return ReactDOM.createPortal(
      <div style={{ position: 'fixed', inset: 0, zIndex: 60, display: 'grid', placeItems: 'center', padding: '24px' }}>
        <div onClick={busy ? undefined : onClose} style={{ position: 'absolute', inset: 0, background: 'rgba(8,12,18,0.66)', backdropFilter: 'blur(3px)' }} />
        <div className="portal-modal" style={{ position: 'relative', width: '100%', maxWidth: '480px', maxHeight: 'calc(100vh - 48px)', background: 'var(--surface-card)', border: '1px solid var(--border-light)', borderRadius: 'var(--radius-lg)', boxShadow: 'var(--shadow-lg)', overflow: 'hidden', display: 'flex', flexDirection: 'column' }}>
          <div style={{ padding: '20px 24px', borderBottom: '1px solid var(--border)', borderTop: '2px solid var(--accent)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
            <h3 style={{ margin: 0, fontSize: '17px', fontWeight: 700, color: 'var(--text-primary)' }}>{title}</h3>
            <button onClick={onClose} style={{ background: 'transparent', border: 'none', color: 'var(--text-secondary)', cursor: 'pointer', fontSize: '16px' }}><i className="fas fa-xmark" /></button>
          </div>
          <div style={{ flex: 1, overflowY: 'auto', padding: '24px', display: 'flex', flexDirection: 'column', gap: '16px' }}>
            {children}
            {error && (
              <div style={{ display: 'flex', alignItems: 'center', gap: '8px', padding: '10px 12px', borderRadius: 'var(--radius)', background: 'rgba(239,68,68,0.10)', border: '1px solid rgba(239,68,68,0.3)', color: 'var(--red-500)', fontSize: '12.5px' }}>
                <i className="fas fa-triangle-exclamation" />{error}
              </div>
            )}
          </div>
          <div style={{ padding: '18px 24px', borderTop: '1px solid var(--border)', display: 'flex', gap: '10px', justifyContent: 'flex-end' }}>
            <Button variant="glass" size="sm" onClick={onClose} disabled={busy}>Отмена</Button>
            <Button variant="primary" size="sm" icon={busy ? undefined : 'fas fa-check'} onClick={onSubmit} disabled={busy}>{busy ? 'Сохранение…' : (submitLabel || 'Сохранить')}</Button>
          </div>
        </div>
      </div>,
      document.body,
    );
  }

  function Toolbar({ placeholder, value, onChange, onAdd, addLabel }) {
    return (
      <div style={{ display: 'flex', gap: '12px', marginBottom: '18px' }}>
        <div style={{ flex: 1, maxWidth: '340px' }}><Input icon="fas fa-magnifying-glass" placeholder={placeholder} value={value} onChange={onChange} fullWidth /></div>
        <div style={{ flex: 1 }} />
        {onAdd && <Button variant="primary" size="md" icon="fas fa-plus" onClick={onAdd}>{addLabel}</Button>}
      </div>
    );
  }

  // textarea с лейблом (в DS нет компонента textarea)
  function TextArea({ label, value, onChange, placeholder, rows = 5 }) {
    return (
      <div>
        <label style={{ display: 'block', fontSize: 'var(--fs-xs)', color: 'var(--text-secondary)', fontWeight: 500, marginBottom: '6px' }}>{label}</label>
        <textarea rows={rows} value={value} onChange={onChange} placeholder={placeholder}
          style={{ width: '100%', background: 'var(--surface-base)', border: '1px solid var(--border)', borderRadius: 'var(--radius)', color: 'var(--text-primary)', padding: '12px 14px', font: 'inherit', fontSize: '13px', resize: 'vertical', boxSizing: 'border-box' }} />
      </div>
    );
  }

  function Toggle({ label, value, onChange }) {
    return (
      <label style={{ display: 'flex', alignItems: 'center', gap: '10px', cursor: 'pointer', fontSize: '13px', color: 'var(--text-secondary)' }}>
        <input type="checkbox" checked={value} onChange={(e) => onChange(e.target.checked)} style={{ width: '16px', height: '16px', accentColor: 'var(--accent)' }} />
        {label}
      </label>
    );
  }

  // Расшифровка кодов ошибок API в человекочитаемый текст.
  function errText(e) {
    const m = {
      slug_taken: 'Такой slug уже занят.',
      version_exists: 'Такая версия для этого продукта уже существует.',
      license_key_taken: 'Лицензия с таким ключом уже есть.',
      user_not_found: 'Пользователь с таким email не найден.',
      product_not_found: 'Продукт не найден.',
      email_taken: 'Пользователь с таким email уже существует.',
    };
    return (e && m[e.code]) || 'Не удалось сохранить. Проверьте поля и попробуйте снова.';
  }

  // Хук формы: значения + busy + error.
  function useForm(initial) {
    const [v, setV] = React.useState(initial);
    const [busy, setBusy] = React.useState(false);
    const [error, setError] = React.useState('');
    const set = (k) => (e) => setV((s) => ({ ...s, [k]: e && e.target ? e.target.value : e }));
    const reset = () => { setV(initial); setError(''); setBusy(false); };
    return { v, setV, set, busy, setBusy, error, setError, reset };
  }

  async function withDelete(reload, fn, confirmText) {
    if (!window.confirm(confirmText)) return;
    try { await fn(); await reload(); }
    catch (e) { window.alert('Не удалось выполнить: ' + ((e && e.code) || 'ошибка')); }
  }

  // ---- Продукты ----
  function AdminProducts({ reload }) {
    const [drawer, setDrawer] = React.useState(false);
    const [q, setQ] = React.useState('');
    const f = useForm({ name: '', slug: '', tagline: '', platform: '' });

    const open = () => { f.reset(); setDrawer(true); };
    const submit = async () => {
      if (!f.v.name.trim() || !f.v.slug.trim()) { f.setError('Укажите название и slug.'); return; }
      f.setBusy(true); f.setError('');
      try {
        await D.admin.createProduct({
          name: f.v.name.trim(), slug: f.v.slug.trim(),
          ...(f.v.tagline.trim() ? { tagline: f.v.tagline.trim() } : {}),
          ...(f.v.platform.trim() ? { platform: f.v.platform.trim() } : {}),
        });
        setDrawer(false); await reload();
      } catch (e) { f.setError(errText(e)); f.setBusy(false); }
    };

    const rows = D.products.filter((p) =>
      !q || `${p.name} ${p.slug} ${p.tagline || ''}`.toLowerCase().includes(q.toLowerCase()));

    return (
      <div>
        <PageHeading eyebrow="Управление" title="Продукты" subtitle="Каталог продуктов портала. Версии и лицензии привязываются к продукту." />
        <Toolbar placeholder="Поиск по названию" value={q} onChange={(e) => setQ(e.target.value)} onAdd={open} addLabel="Добавить продукт" />
        <TableShell head={['Продукт', 'Slug', 'Версий', 'Лицензий', 'Описание', '']}>
          {rows.length === 0 ? <Empty cols={6} text="Продукты не найдены" /> : rows.map((p) => (
            <Row key={p.id}>
              <td style={{ ...cell, color: 'var(--text-primary)', fontWeight: 600 }}><div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}><i className={p.icon} style={{ color: 'var(--accent-light)' }} />{p.name}</div></td>
              <td style={cell}><Mono>{p.slug}</Mono></td>
              <td style={cell}>{p.versions_count != null ? p.versions_count : D.versionsFor(p.id).length}</td>
              <td style={cell}>{p.licenses_count != null ? p.licenses_count : D.adminLicenses.filter((l) => l.product === p.name).length}</td>
              <td style={{ ...cell, maxWidth: '320px', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{p.tagline}</td>
              <td style={{ ...cell, textAlign: 'right', whiteSpace: 'nowrap' }}>
                <IconBtn icon="fas fa-trash" title="Удалить" danger onClick={() => withDelete(reload, () => D.admin.deleteProduct(p.id), `Удалить продукт «${p.name}»? Будут удалены его версии и лицензии.`)} />
              </td>
            </Row>
          ))}
        </TableShell>
        <Drawer open={drawer} title="Новый продукт" onClose={() => setDrawer(false)} onSubmit={submit} submitLabel="Создать" busy={f.busy} error={f.error}>
          <Input label="Название" placeholder="Напр. VR Expert" value={f.v.name} onChange={f.set('name')} fullWidth />
          <Input label="Slug (латиница, дефисы)" icon="fas fa-link" placeholder="vr-expert" value={f.v.slug} onChange={f.set('slug')} fullWidth />
          <Input label="Краткое описание" placeholder="Что делает продукт" value={f.v.tagline} onChange={f.set('tagline')} fullWidth />
          <Select label="Платформа" value={f.v.platform} onChange={f.set('platform')} placeholder="Выберите платформу" options={['Windows 10/11 x64', 'Windows 10/11 x64 · GPU NVIDIA', 'Linux x64']} fullWidth />
        </Drawer>
      </div>
    );
  }

  // ---- Версии ----
  function AdminVersions({ reload }) {
    const [drawer, setDrawer] = React.useState(false);
    const [prod, setProd] = React.useState('all');
    const f = useForm({ product_id: '', version: '', release_date: '', yadisk_url: '', size: '', changelog: '', is_critical: false });

    const open = () => { f.reset(); f.setV((s) => ({ ...s, product_id: D.products[0] ? String(D.products[0].id) : '' })); setDrawer(true); };
    const submit = async () => {
      if (!f.v.product_id || !f.v.version.trim() || !f.v.release_date || !f.v.yadisk_url.trim()) {
        f.setError('Заполните продукт, версию, дату и ссылку.'); return;
      }
      f.setBusy(true); f.setError('');
      try {
        await D.admin.createVersion({
          product_id: Number(f.v.product_id), version: f.v.version.trim(),
          release_date: f.v.release_date, yadisk_url: f.v.yadisk_url.trim(),
          is_critical: !!f.v.is_critical,
          ...(f.v.size.trim() ? { size: f.v.size.trim() } : {}),
          ...(f.v.changelog.trim() ? { changelog: f.v.changelog.trim() } : {}),
        });
        setDrawer(false); await reload();
      } catch (e) { f.setError(errText(e)); f.setBusy(false); }
    };

    const rows = D.versions
      .filter((v) => prod === 'all' || v.product_id === Number(prod))
      .sort((a, b) => D.parseDate(b.release_date) - D.parseDate(a.release_date));

    return (
      <div>
        <PageHeading eyebrow="Управление" title="Версии" subtitle="Релизы продуктов. Поле «ссылка Я.Диск» — источник дистрибутива, отдаётся клиенту по правам лицензии." />
        <div style={{ display: 'flex', gap: '12px', marginBottom: '18px', alignItems: 'flex-end' }}>
          <div style={{ width: '240px' }}>
            <Select label="Продукт" value={prod} onChange={(e) => setProd(e.target.value)} options={[{ value: 'all', label: 'Все продукты' }, ...D.products.map((p) => ({ value: String(p.id), label: p.name }))]} fullWidth />
          </div>
          <div style={{ flex: 1 }} />
          <Button variant="primary" size="md" icon="fas fa-plus" onClick={open}>Добавить версию</Button>
        </div>
        <TableShell head={['Продукт', 'Версия', 'Дата выпуска', 'Размер', 'Ссылка Я.Диск', '']}>
          {rows.length === 0 ? <Empty cols={6} text="Версий нет" /> : rows.map((v) => {
            const p = D.productById(v.product_id);
            return (
              <Row key={v.id}>
                <td style={{ ...cell, color: 'var(--text-primary)', fontWeight: 600 }}>{p ? p.name : v.product_name}</td>
                <td style={cell}><Mono><span style={{ color: 'var(--text-primary)', fontWeight: 700 }}>v{v.version}</span></Mono>{v.critical && <span style={{ fontSize: '9px', fontWeight: 700, letterSpacing: '0.06em', textTransform: 'uppercase', color: 'var(--accent-light)', background: 'var(--accent-soft)', borderRadius: '4px', padding: '2px 6px', marginLeft: '8px' }}>важное</span>}</td>
                <td style={cell}>{D.formatDate(v.release_date)}</td>
                <td style={cell}>{v.size}</td>
                <td style={{ ...cell, maxWidth: '260px' }}><span style={{ display: 'flex', alignItems: 'center', gap: '8px', color: 'var(--accent-light)' }}><i className="fab fa-yandex" style={{ opacity: 0.7 }} /><span style={{ overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap', fontFamily: 'var(--font-mono)', fontSize: '12px' }}>{v.yadisk_url}</span></span></td>
                <td style={{ ...cell, textAlign: 'right', whiteSpace: 'nowrap' }}>
                  <IconBtn icon="fas fa-trash" title="Удалить" danger onClick={() => withDelete(reload, () => D.admin.deleteVersion(v.id), `Удалить версию v${v.version}?`)} />
                </td>
              </Row>
            );
          })}
        </TableShell>
        <Drawer open={drawer} title="Новая версия" onClose={() => setDrawer(false)} onSubmit={submit} submitLabel="Опубликовать" busy={f.busy} error={f.error}>
          <Select label="Продукт" value={f.v.product_id} onChange={f.set('product_id')} options={D.products.map((p) => ({ value: String(p.id), label: p.name }))} fullWidth />
          <Input label="Номер версии" icon="fas fa-code-branch" placeholder="1.6.3" value={f.v.version} onChange={f.set('version')} fullWidth />
          <ThemedDate label="Дата выпуска" value={f.v.release_date} onChange={f.set('release_date')} fullWidth />
          <Input label="Размер дистрибутива" icon="fas fa-hard-drive" placeholder="3.4 ГБ" value={f.v.size} onChange={f.set('size')} fullWidth />
          <Input label="Ссылка на Я.Диск" icon="fas fa-link" placeholder="https://disk.yandex.ru/d/…" value={f.v.yadisk_url} onChange={f.set('yadisk_url')} fullWidth />
          <TextArea label="Changelog (по строке на пункт)" value={f.v.changelog} onChange={f.set('changelog')} placeholder="Список изменений, по строке на пункт" />
          <Toggle label="Важное обновление" value={f.v.is_critical} onChange={(c) => f.setV((s) => ({ ...s, is_critical: c }))} />
        </Drawer>
      </div>
    );
  }

  // ---- Лицензии ----
  function AdminLicenses({ reload }) {
    const [drawer, setDrawer] = React.useState(false);
    const [q, setQ] = React.useState('');
    const f = useForm({ product_id: '', user_email: '', license_key: '', valid_until: '', updates_until: '', seats: '' });

    const open = () => { f.reset(); f.setV((s) => ({ ...s, product_id: D.products[0] ? String(D.products[0].id) : '' })); setDrawer(true); };
    const submit = async () => {
      if (!f.v.product_id || !f.v.user_email.trim() || !f.v.license_key.trim()) {
        f.setError('Укажите продукт, email пользователя и ключ.'); return;
      }
      f.setBusy(true); f.setError('');
      try {
        await D.admin.createLicense({
          product_id: Number(f.v.product_id), user_email: f.v.user_email.trim(), license_key: f.v.license_key.trim(),
          ...(f.v.valid_until ? { valid_until: f.v.valid_until } : {}),
          ...(f.v.updates_until ? { updates_until: f.v.updates_until } : {}),
          ...(f.v.seats ? { seats: Number(f.v.seats) } : {}),
        });
        setDrawer(false); await reload();
      } catch (e) { f.setError(errText(e)); f.setBusy(false); }
    };

    const rows = D.adminLicenses.filter((l) =>
      !q || `${l.key} ${l.product} ${l.user} ${l.org}`.toLowerCase().includes(q.toLowerCase()));

    return (
      <div>
        <PageHeading eyebrow="Управление" title="Лицензии" subtitle="Привязка продукта к пользователю. «Право на обновления» отделено от срока действия лицензии — оно определяет доступ к новым версиям." />
        <Toolbar placeholder="Поиск по ключу, организации" value={q} onChange={(e) => setQ(e.target.value)} onAdd={open} addLabel="Выдать лицензию" />
        <TableShell head={['Ключ', 'Продукт', 'Пользователь', 'Срок действия', 'Обновления до', 'Статус', '']}>
          {rows.length === 0 ? <Empty cols={7} text="Лицензии не найдены" /> : rows.map((l) => {
            const st = D.updatesStatus(l.updates_until);
            return (
              <Row key={l.id}>
                <td style={cell}><Mono>{l.key}</Mono></td>
                <td style={{ ...cell, color: 'var(--text-primary)', fontWeight: 600 }}>{l.product}</td>
                <td style={cell}><div style={{ color: 'var(--text-primary)' }}>{l.user}</div><div style={{ fontSize: '11.5px', color: 'var(--text-muted)' }}>{l.org}</div></td>
                <td style={cell}>{l.valid_until ? D.formatDate(l.valid_until) : 'Бессрочно'}</td>
                <td style={cell}>{l.updates_until ? D.formatDate(l.updates_until) : 'Без огранич.'}</td>
                <td style={cell}><StatusBadge tone={st.tone} dot>{st.code === 'expired' ? 'Истекло' : st.code === 'soon' ? 'Истекает' : st.code === 'unlimited' ? 'Бессрочно' : 'Активно'}</StatusBadge></td>
                <td style={{ ...cell, textAlign: 'right', whiteSpace: 'nowrap' }}>
                  <IconBtn icon="fas fa-trash" title="Отозвать" danger onClick={() => withDelete(reload, () => D.admin.deleteLicense(l.id), `Отозвать лицензию ${l.key}?`)} />
                </td>
              </Row>
            );
          })}
        </TableShell>
        <Drawer open={drawer} title="Выдать лицензию" onClose={() => setDrawer(false)} onSubmit={submit} submitLabel="Выдать" busy={f.busy} error={f.error}>
          <Select label="Продукт" value={f.v.product_id} onChange={f.set('product_id')} options={D.products.map((p) => ({ value: String(p.id), label: p.name }))} fullWidth />
          <Input label="Пользователь (email)" icon="fas fa-envelope" placeholder="name@org.gov" value={f.v.user_email} onChange={f.set('user_email')} fullWidth />
          <Input label="Ключ лицензии" icon="fas fa-key" placeholder="LAN-VRE-2026-0000" value={f.v.license_key} onChange={f.set('license_key')} fullWidth />
          <ThemedDate label="Срок действия (пусто = бессрочно)" value={f.v.valid_until} onChange={f.set('valid_until')} fullWidth />
          <ThemedDate label="Право на обновления до" value={f.v.updates_until} onChange={f.set('updates_until')} fullWidth />
          <Input label="Рабочих мест" type="number" placeholder="5" value={f.v.seats} onChange={f.set('seats')} fullWidth />
        </Drawer>
      </div>
    );
  }

  // ---- Пользователи ----
  function AdminUsers({ reload }) {
    const [drawer, setDrawer] = React.useState(false);
    const [q, setQ] = React.useState('');
    const f = useForm({ display_name: '', email: '', org: '', role: 'client', password: '' });

    const open = () => { f.reset(); setDrawer(true); };
    const submit = async () => {
      if (!f.v.email.trim() || !f.v.password) { f.setError('Укажите email и пароль.'); return; }
      if (f.v.password.length < 8) { f.setError('Пароль — минимум 8 символов.'); return; }
      f.setBusy(true); f.setError('');
      try {
        await D.admin.createUser({
          email: f.v.email.trim(), password: f.v.password, role: f.v.role,
          ...(f.v.display_name.trim() ? { display_name: f.v.display_name.trim() } : {}),
          ...(f.v.org.trim() ? { org: f.v.org.trim() } : {}),
        });
        setDrawer(false); await reload();
      } catch (e) { f.setError(errText(e)); f.setBusy(false); }
    };

    const rows = D.adminUsers.filter((u) =>
      !q || `${u.display_name} ${u.email} ${u.org}`.toLowerCase().includes(q.toLowerCase()));

    return (
      <div>
        <PageHeading eyebrow="Управление" title="Пользователи" subtitle="Клиенты и администраторы портала. Владелец лицензии — пользователь (представитель организации)." />
        <Toolbar placeholder="Поиск по email, организации" value={q} onChange={(e) => setQ(e.target.value)} onAdd={open} addLabel="Добавить пользователя" />
        <TableShell head={['Пользователь', 'Email', 'Организация', 'Роль', 'Лицензий', 'Создан']}>
          {rows.length === 0 ? <Empty cols={6} text="Пользователи не найдены" /> : rows.map((u) => (
            <Row key={u.id}>
              <td style={{ ...cell }}><div style={{ display: 'flex', alignItems: 'center', gap: '11px' }}><span style={{ width: '32px', height: '32px', borderRadius: '50%', display: 'grid', placeItems: 'center', background: u.role === 'admin' ? 'rgba(37,99,235,0.18)' : 'var(--surface-overlay)', border: '1px solid var(--border)', color: u.role === 'admin' ? 'var(--accent-light)' : 'var(--text-secondary)', fontSize: '11px', fontWeight: 700 }}>{u.display_name.split(' ').map((s) => s[0]).slice(0, 2).join('')}</span><span style={{ color: 'var(--text-primary)', fontWeight: 600 }}>{u.display_name}</span></div></td>
              <td style={cell}><Mono>{u.email}</Mono></td>
              <td style={cell}>{u.org}</td>
              <td style={cell}>{u.role === 'admin' ? <StatusBadge tone="accent">Администратор</StatusBadge> : <span style={{ color: 'var(--text-secondary)' }}>Клиент</span>}</td>
              <td style={cell}>{u.licenses}</td>
              <td style={cell}>{D.formatDate(u.created_at)}</td>
            </Row>
          ))}
        </TableShell>
        <Drawer open={drawer} title="Новый пользователь" onClose={() => setDrawer(false)} onSubmit={submit} submitLabel="Создать" busy={f.busy} error={f.error}>
          <Input label="ФИО / представитель" placeholder="И. С. Орлов" value={f.v.display_name} onChange={f.set('display_name')} fullWidth />
          <Input label="Email" icon="fas fa-envelope" placeholder="name@org.gov" value={f.v.email} onChange={f.set('email')} fullWidth />
          <Input label="Организация" icon="fas fa-building" placeholder="Наименование" value={f.v.org} onChange={f.set('org')} fullWidth />
          <Input label="Пароль (мин. 8 символов)" icon="fas fa-lock" type="password" placeholder="••••••••" value={f.v.password} onChange={f.set('password')} fullWidth />
          <Select label="Роль" value={f.v.role} onChange={f.set('role')} options={[{ value: 'client', label: 'Клиент' }, { value: 'admin', label: 'Администратор' }]} fullWidth />
        </Drawer>
      </div>
    );
  }

  // ---- Журнал выдач ----
  function AdminLog() {
    return (
      <div>
        <PageHeading eyebrow="Аудит" title="Журнал выдач ссылок" subtitle="Каждая выдача ссылки на дистрибутив фиксируется: пользователь, версия, IP и время. Доказуемая цепочка поставки обновлений." />
        <div style={{ display: 'flex', gap: '16px', marginBottom: '18px' }}>
          <div style={{ flex: 1, background: 'var(--surface-card)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', padding: '16px 20px', display: 'flex', alignItems: 'center', gap: '14px' }}>
            <i className="fas fa-list-check" style={{ color: 'var(--accent-light)', fontSize: '18px' }} />
            <div><div style={{ fontSize: '22px', fontWeight: 800, color: 'var(--text-primary)' }}>{D.adminLog.length}</div><div style={{ fontSize: '12px', color: 'var(--text-muted)' }}>выдач за период</div></div>
          </div>
          <div style={{ flex: 1, background: 'var(--surface-card)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', padding: '16px 20px', display: 'flex', alignItems: 'center', gap: '14px' }}>
            <i className="fas fa-users" style={{ color: 'var(--accent-light)', fontSize: '18px' }} />
            <div><div style={{ fontSize: '22px', fontWeight: 800, color: 'var(--text-primary)' }}>{new Set(D.adminLog.map((l) => l.org)).size}</div><div style={{ fontSize: '12px', color: 'var(--text-muted)' }}>организаций</div></div>
          </div>
          <div style={{ flex: 1, background: 'var(--surface-card)', border: '1px solid var(--border)', borderRadius: 'var(--radius-lg)', padding: '16px 20px', display: 'flex', alignItems: 'center', gap: '14px' }}>
            <span style={{ width: '10px', height: '10px', borderRadius: '50%', background: 'var(--green-500)', boxShadow: '0 0 8px 1px rgba(34,197,94,0.7)' }} />
            <div><div style={{ fontSize: '13px', fontWeight: 700, color: 'var(--text-primary)' }}>Аудит активен</div><div style={{ fontSize: '12px', color: 'var(--text-muted)' }}>запись в БД при каждой выдаче</div></div>
          </div>
        </div>
        <TableShell head={['Время', 'Пользователь', 'Организация', 'Продукт', 'Версия', 'IP-адрес']}>
          {D.adminLog.length === 0 ? <Empty cols={6} text="Выдач пока не было" /> : D.adminLog.map((l) => (
            <Row key={l.id}>
              <td style={{ ...cell, color: 'var(--text-primary)', whiteSpace: 'nowrap' }}><i className="far fa-clock" style={{ marginRight: '8px', color: 'var(--text-muted)' }} />{l.created_at}</td>
              <td style={cell}>{l.user}</td>
              <td style={cell}>{l.org}</td>
              <td style={{ ...cell, color: 'var(--text-primary)', fontWeight: 600 }}>{l.product}</td>
              <td style={cell}><Mono>v{l.version}</Mono></td>
              <td style={cell}><Mono>{l.ip}</Mono></td>
            </Row>
          ))}
        </TableShell>
      </div>
    );
  }

  Object.assign(window, { AdminProducts, AdminVersions, AdminLicenses, AdminUsers, AdminLog });
})();
