// ════════════════════════════════════════════════════════════════
// /admin/users — Users management + InviteModal
// ════════════════════════════════════════════════════════════════

function UsersTable({ currentUser, onRoute }) {
  const A = window.SDH_ADMIN;
  const [search, setSearch] = React.useState('');
  const [roleFilter, setRoleFilter] = React.useState('all');
  const [statusFilter, setStatusFilter] = React.useState('all');
  const [openInvite, setOpenInvite] = React.useState(false);
  const [createdInvite, setCreatedInvite] = React.useState(null);

  const isSuperAdmin = currentUser.role === 'super_admin';

  // RBAC: admin не видит super_admin'ов
  let users = A.users;
  if (!isSuperAdmin) users = users.filter(u => u.role !== 'super_admin');
  if (search) {
    const q = search.toLowerCase();
    users = users.filter(u => u.name.toLowerCase().includes(q) || u.email.toLowerCase().includes(q));
  }
  if (roleFilter !== 'all') users = users.filter(u => u.role === roleFilter);
  if (statusFilter !== 'all') users = users.filter(u => u.status === statusFilter);

  const activeCount = A.users.filter(u => u.status === 'active').length;
  const invitedCount = A.invites.filter(i => i.status === 'pending').length;

  return (
    <div className="sdh-fade">
      <PageHeader
        section="управление"
        title="Пользователи и доступ"
        accent="доступ"
        subtitle={`${activeCount} активных учётных записей, ${invitedCount} приглашений в ожидании. Принцип least privilege: каждый видит только то, что нужно для своих задач.`}
        right={
          <div style={{ display: 'flex', gap: 8 }}>
            <button className="sdh-btn" onClick={() => onRoute('admin.invites')}>Все приглашения</button>
            <button className="sdh-btn sdh-btn--bronze" onClick={() => setOpenInvite(true)}>
              <svg width="12" height="12" viewBox="0 0 12 12" fill="none" stroke="currentColor" strokeWidth="1.5">
                <path d="M6 2v8M2 6h8" strokeLinecap="round" />
              </svg>
              Пригласить
            </button>
          </div>
        }
      />

      <CommandBar sticky={false}
        left={
          <>
            <div style={{ position: 'relative' }}>
              <input value={search} onChange={e => setSearch(e.target.value)}
                placeholder="поиск по имени или email"
                style={{
                  background: 'var(--surface-elevated)',
                  border: '1px solid var(--border-default)',
                  borderRadius: 'var(--radius-md)',
                  padding: '7px 12px 7px 30px',
                  fontSize: 13, width: 240, color: 'var(--text-primary)', outline: 'none',
                }} />
              <svg width="14" height="14" viewBox="0 0 14 14" style={{ position: 'absolute', left: 10, top: 9, color: 'var(--text-tertiary)' }} fill="none" stroke="currentColor" strokeWidth="1.3">
                <circle cx="6" cy="6" r="4.2" />
                <line x1="9.5" y1="9.5" x2="12.5" y2="12.5" strokeLinecap="round" />
              </svg>
            </div>
            <span className="sdh-mono-label" style={{ marginBottom: 0, marginLeft: 'var(--space-3)' }}>роль</span>
            <button className={`sdh-chip ${roleFilter === 'all' ? 'is-active' : ''}`} onClick={() => setRoleFilter('all')}>все</button>
            {A.ROLES.filter(r => isSuperAdmin || r.id !== 'super_admin').map(r => (
              <button key={r.id} className={`sdh-chip ${roleFilter === r.id ? 'is-active' : ''}`} onClick={() => setRoleFilter(r.id)}>
                {r.label} <span className="chip-count">{A.users.filter(u => u.role === r.id).length}</span>
              </button>
            ))}
          </>
        }
        right={
          <select value={statusFilter} onChange={e => setStatusFilter(e.target.value)} style={selectStyle}>
            <option value="all">все статусы</option>
            <option value="active">активны</option>
            <option value="expired">истекли</option>
            <option value="revoked">отозваны</option>
          </select>
        }
      />

      <section className="sdh-container" style={{ paddingTop: 'var(--space-6)', paddingBottom: 'var(--space-16)' }}>
        <div className="sdh-mono-label" style={{ marginBottom: 'var(--space-3)' }}>
          <span className="sdh-num" style={{ color: 'var(--text-primary)', fontSize: 13 }}>{users.length}</span> пользователей в выборке
        </div>

        <div style={{
          background: 'var(--surface-elevated)',
          border: '1px solid var(--border-subtle)',
          borderRadius: 'var(--radius-xl)',
          overflow: 'hidden',
        }}>
          <div style={{
            display: 'grid',
            gridTemplateColumns: '2.4fr 110px 110px 140px 1fr',
            padding: '10px 16px', gap: 12,
            background: 'var(--surface-sunken)',
            borderBottom: '1px solid var(--border-subtle)',
          }}>
            <div className="sdh-mono-label">пользователь</div>
            <div className="sdh-mono-label">роль</div>
            <div className="sdh-mono-label">статус</div>
            <div className="sdh-mono-label"><InfoLabel
              title="Срок токена"
              what="Дата, когда Bearer токен этого пользователя перестанет работать."
              why="Продлите до истечения, иначе доступ оборвётся прямо во время работы. Чем выше роль — тем больше срок (super-admin бессрочный, viewer 90 дней)."
            >токен</InfoLabel></div>
            <div className="sdh-mono-label" style={{ textAlign: 'right' }}>действия</div>
          </div>

          {users.map(u => (
            <UserRow key={u.id} user={u} currentUser={currentUser} />
          ))}

          {users.length === 0 && (
            <EmptyState title="Никого не нашлось" hint="Сбросьте фильтры или измените поисковый запрос." />
          )}
        </div>
      </section>

      {openInvite && (
        <InviteModal currentUser={currentUser}
          onClose={() => setOpenInvite(false)}
          onCreated={(inv) => { setOpenInvite(false); setCreatedInvite(inv); }} />
      )}
      {createdInvite && (
        <InviteCreatedModal invite={createdInvite} onClose={() => setCreatedInvite(null)} />
      )}
    </div>
  );
}

function UserRow({ user, currentUser }) {
  const isSelf = user.id === currentUser.id;
  const canEditRole = currentUser.role === 'super_admin' && !isSelf;
  const canRevoke =
    (currentUser.role === 'super_admin' && !isSelf) ||
    (currentUser.role === 'admin' && !isSelf && ['collaborator', 'viewer', 'agent'].includes(user.role));

  return (
    <div style={{
      display: 'grid',
      gridTemplateColumns: '2.4fr 110px 110px 140px 1fr',
      padding: '12px 16px', gap: 12,
      alignItems: 'center',
      borderBottom: '1px solid var(--border-subtle)',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, minWidth: 0 }}>
        <UserAvatar name={user.name} role={user.role} size={36} />
        <div style={{ minWidth: 0 }}>
          <div style={{ fontSize: 13.5, fontWeight: 500, color: 'var(--text-primary)', display: 'flex', alignItems: 'center', gap: 6 }}>
            {user.name}
            {isSelf && <CategoryPill hue="bronze" small>вы</CategoryPill>}
          </div>
          <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)', fontFamily: 'var(--font-mono)', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
            {user.email}
          </div>
          {user.note && (
            <div style={{ fontSize: 11.5, color: 'var(--text-tertiary)', fontStyle: 'italic', marginTop: 2 }}>
              {user.note}
            </div>
          )}
        </div>
      </div>
      <div><RoleBadge role={user.role} size="sm" /></div>
      <div><StatusDot status={user.status} /></div>
      <div>
        {user.token_expires_at === null
          ? <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--brand-bronze-deep)' }}>∞ бессрочный</span>
          : user.status === 'expired'
            ? <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--hue-rose)' }}>истёк</span>
            : user.token_warning
              ? <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--warning)', fontWeight: 600 }}>{user.days_left} дн</span>
              : <span style={{ fontFamily: 'var(--font-mono)', fontSize: 12, color: 'var(--text-secondary)' }}>{user.days_left} дн</span>}
      </div>
      <div style={{ display: 'flex', gap: 4, justifyContent: 'flex-end', flexWrap: 'wrap' }}>
        {user.token_warning && (
          <button className="sdh-btn sdh-btn--bronze" style={{ fontSize: 11, padding: '4px 10px' }}>Продлить</button>
        )}
        {canEditRole && (
          <button className="sdh-btn sdh-btn--ghost" style={{ fontSize: 11, padding: '4px 8px' }} title="Изменить роль">
            роль
          </button>
        )}
        {canRevoke && user.status === 'active' && (
          <button className="sdh-btn sdh-btn--ghost" style={{ fontSize: 11, padding: '4px 8px', color: 'var(--hue-rose)' }}>
            revoke
          </button>
        )}
        <button className="sdh-btn sdh-btn--ghost" style={{ fontSize: 11, padding: '4px 8px' }}>audit</button>
      </div>
    </div>
  );
}

// ── Invite modal ────────────────────────────────────────────────
function InviteModal({ currentUser, onClose, onCreated }) {
  const A = window.SDH_ADMIN;
  const isSuperAdmin = currentUser.role === 'super_admin';
  const availableRoles = A.ROLES.filter(r => {
    if (r.id === 'super_admin') return false;
    if (r.id === 'admin' && !isSuperAdmin) return false;
    return true;
  });

  const [email, setEmail] = React.useState('');
  const [role, setRole] = React.useState('collaborator');
  const [ttl, setTtl] = React.useState(A.TTL.collaborator.days);
  const [note, setNote] = React.useState('');
  const [error, setError] = React.useState(null);

  React.useEffect(() => {
    setTtl(A.TTL[role].days || 365);
  }, [role]);

  React.useEffect(() => {
    function onKey(e) { if (e.key === 'Escape') onClose(); }
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);

  async function submit(e) {
    e.preventDefault();
    if (!email.includes('@')) { setError('Введите корректный email'); return; }
    setError(null);

    // API mode
    if (window.SDH_USE_API && window.SDH_API) {
      try {
        const resp = await window.SDH_API.post('/api/admin/invites', {
          email, role, ttl_days: ttl || undefined, note: note || undefined,
        });
        const newInvite = {
          id: resp.id, email, role, ttl_days: ttl, note,
          token: resp.invite_token,
          status: 'pending',
          sent_at: new Date().toISOString(),
          inviter: currentUser.name,
          url: resp.redeem_url,
        };
        onCreated(newInvite);
        if (window.SDH_HYDRATE && window.SDH_HYDRATE.refreshInvites) {
          window.SDH_HYDRATE.refreshInvites();
        }
      } catch (err) {
        const msg = err && err.status === 403 ? 'Эта роль вам не разрешена (нужен super-admin)'
                  : err && err.status === 409 ? 'Email уже активен в системе'
                  : (err && err.message) || 'Ошибка создания invite';
        setError(msg);
      }
      return;
    }

    // Mock
    const token = 'inv_' + Math.random().toString(36).slice(2, 8) + Math.random().toString(36).slice(2, 8);
    const newInvite = {
      id: 'inv_new', email, role, ttl_days: ttl, note,
      token,
      status: 'pending',
      sent_at: new Date().toISOString(),
      inviter: currentUser.name,
      url: `https://analytics.simbiosislab.online/invite/${token}`,
    };
    onCreated(newInvite);
  }

  const roleCfg = A.ROLES.find(r => r.id === role);

  return (
    <div onClick={onClose} style={modalShellStyle}>
      <form onClick={e => e.stopPropagation()} onSubmit={submit} className="sdh-fade" style={modalCardStyle}>
        <button type="button" onClick={onClose} className="sdh-btn sdh-btn--ghost"
          style={{ position: 'absolute', top: 14, right: 14, padding: 6 }}>
          <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5">
            <path d="M3 3l8 8m0-8l-8 8" strokeLinecap="round" />
          </svg>
        </button>

        <span className="sdh-section-label">пригласить пользователя</span>
        <h2 style={{ margin: '0 0 var(--space-2)', fontSize: 24, fontWeight: 600, letterSpacing: '-0.02em' }}>
          Новое <em style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic', color: 'var(--brand-bronze-deep)' }}>приглашение</em>
        </h2>
        <p className="sdh-quote" style={{ margin: '0 0 var(--space-6)' }}>
          Email на этом этапе не отправляется. Создаём ссылку, вы передаёте её получателю через свой канал (Telegram, встреча, ваш почтовый клиент).
        </p>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 'var(--space-4)' }}>
          <AuthField label="Email получателя">
            <input type="email" required autoFocus value={email} onChange={e => setEmail(e.target.value)}
              placeholder="ivan@example.ru" style={authFieldStyle} />
          </AuthField>

          <div>
            <div className="sdh-mono-label" style={{ marginBottom: 6 }}>
              <InfoLabel
                title="Роль приглашаемого"
                what="Уровень доступа, который получит пользователь после принятия приглашения."
                why="Менять роль потом можно только super-admin. Выбирайте минимально достаточную: viewer для гостей, collaborator для команды, admin только для доверенных, agent для машинных интеграций."
              >Роль</InfoLabel>
            </div>
            <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
              {availableRoles.map(r => (
                <label key={r.id} style={{
                  display: 'grid', gridTemplateColumns: '20px 1fr', gap: 10,
                  padding: 'var(--space-3)', cursor: 'pointer',
                  background: role === r.id ? `var(--hue-${r.hue === 'bronze' ? 'amber' : r.hue}-subtle)` : 'transparent',
                  border: `1px solid ${role === r.id ? `var(--hue-${r.hue === 'bronze' ? 'amber' : r.hue})` : 'var(--border-subtle)'}`,
                  borderRadius: 'var(--radius-md)',
                }}>
                  <input type="radio" name="role" value={r.id} checked={role === r.id}
                    onChange={() => setRole(r.id)} style={{ accentColor: 'var(--brand-bronze)' }} />
                  <div>
                    <div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 2 }}>
                      <RoleBadge role={r.id} size="sm" />
                      <span className="sdh-mono-label" style={{ marginBottom: 0 }}>
                        TTL по умолч: {A.TTL[r.id].days ? `${A.TTL[r.id].days} дн` : '∞'}
                      </span>
                    </div>
                    <p style={{ margin: 0, fontSize: 12.5, color: 'var(--text-tertiary)', lineHeight: 1.4 }}>
                      {r.what}
                    </p>
                  </div>
                </label>
              ))}
            </div>
          </div>

          <AuthField label="Срок токена (дней)">
            <input type="number" min="1" max="730" value={ttl}
              onChange={e => setTtl(Number(e.target.value))}
              style={authFieldStyle} />
          </AuthField>

          <AuthField label="Заметка (опционально, видна только админам)">
            <textarea value={note} onChange={e => setNote(e.target.value)}
              placeholder="например: кандидат на роль аналитика, рекомендован Лидой"
              style={{ ...authFieldStyle, minHeight: 60, resize: 'vertical', fontFamily: 'var(--font-sans)' }} />
          </AuthField>

          {error && (
            <div style={{
              padding: '8px 10px', background: 'var(--hue-rose-subtle)',
              border: '1px solid var(--hue-rose)', borderRadius: 'var(--radius-md)',
              fontSize: 12, color: 'var(--hue-rose)',
            }}>{error}</div>
          )}
        </div>

        <div style={{
          display: 'flex', justifyContent: 'flex-end', gap: 8,
          marginTop: 'var(--space-6)', paddingTop: 'var(--space-4)',
          borderTop: '1px solid var(--border-subtle)',
        }}>
          <button type="button" className="sdh-btn sdh-btn--ghost" onClick={onClose}>Отмена</button>
          <button type="submit" className="sdh-btn sdh-btn--bronze">Создать приглашение</button>
        </div>
      </form>
    </div>
  );
}

// ── Invite created confirmation ─────────────────────────────────
function InviteCreatedModal({ invite, onClose }) {
  return (
    <div onClick={onClose} style={modalShellStyle}>
      <div onClick={e => e.stopPropagation()} className="sdh-fade" style={{ ...modalCardStyle, maxWidth: 560 }}>
        <button onClick={onClose} className="sdh-btn sdh-btn--ghost"
          style={{ position: 'absolute', top: 14, right: 14, padding: 6 }}>
          <svg width="14" height="14" viewBox="0 0 14 14" fill="none" stroke="currentColor" strokeWidth="1.5">
            <path d="M3 3l8 8m0-8l-8 8" strokeLinecap="round" />
          </svg>
        </button>

        <span className="sdh-section-label" style={{ color: 'var(--hue-emerald)' }}>приглашение создано</span>
        <h2 style={{ margin: '0 0 var(--space-3)', fontSize: 24, fontWeight: 600, letterSpacing: '-0.02em' }}>
          Скопируйте <em style={{ fontFamily: 'var(--font-display)', fontStyle: 'italic', color: 'var(--brand-bronze-deep)' }}>ссылку</em> и передайте
        </h2>
        <p className="sdh-quote" style={{ margin: '0 0 var(--space-4)' }}>
          Действительна 7 дней. После — нужно создать новое приглашение. Адресат: <strong style={{ color: 'var(--text-primary)' }}>{invite.email}</strong>, роль <RoleBadge role={invite.role} size="sm" />.
        </p>

        <TokenDisplay value={invite.url} label="invite ссылка · работает один раз" />

        <div style={{
          marginTop: 'var(--space-6)', display: 'flex', justifyContent: 'space-between', alignItems: 'center',
          padding: 'var(--space-3)',
          background: 'var(--surface-sunken)',
          borderRadius: 'var(--radius-md)',
        }}>
          <span className="sdh-mono-label" style={{ marginBottom: 0 }}>
            email уведомление: отключено (deferred · v1.1)
          </span>
          <button className="sdh-btn sdh-btn--ghost" style={{ fontSize: 11, padding: '4px 8px' }} onClick={onClose}>
            закрыть
          </button>
        </div>
      </div>
    </div>
  );
}

const selectStyle = {
  background: 'var(--surface-elevated)',
  border: '1px solid var(--border-default)',
  borderRadius: 'var(--radius-md)',
  padding: '7px 28px 7px 12px',
  fontSize: 13, color: 'var(--text-primary)',
  appearance: 'none',
  backgroundImage: `url("data:image/svg+xml;utf8,<svg xmlns='http://www.w3.org/2000/svg' width='10' height='10' viewBox='0 0 10 10'><path fill='%238A7F70' d='M1 3l4 4 4-4'/></svg>")`,
  backgroundRepeat: 'no-repeat', backgroundPosition: 'right 10px center',
};

const modalShellStyle = {
  position: 'fixed', inset: 0, background: 'var(--surface-overlay)', zIndex: 100,
  display: 'flex', alignItems: 'flex-start', justifyContent: 'center',
  padding: 'var(--space-8) var(--space-4)', overflowY: 'auto',
  backdropFilter: 'blur(2px)',
};
const modalCardStyle = {
  background: 'var(--surface-elevated)',
  borderRadius: 'var(--radius-2xl)',
  border: '1px solid var(--border-subtle)',
  maxWidth: 500, width: '100%',
  padding: 'var(--space-8)',
  boxShadow: 'var(--shadow-xl)',
  position: 'relative',
};

window.UsersTable = UsersTable;
window.InviteModal = InviteModal;
window.InviteCreatedModal = InviteCreatedModal;
window.modalShellStyle = modalShellStyle;
window.modalCardStyle = modalCardStyle;
window.selectStyle = selectStyle;
