/**
 * ICD Test Runner — CRUD: Admin
 * Admin user lifecycle (create → deactivate → login reject → activate →
 * login success → role change → password reset → vault reset → delete),
 * admin settings roundtrip, channel purge.
 */
(function () {
  'use strict';
  var T = window.ICD;
  if (!T) return;
  if (!T.crud) T.crud = {};

  T.crud.admin = async function (testTag) {

    // ── Admin User Lifecycle (create → login fails → activate → login succeeds → cleanup) ──
    if (T.user.role === 'admin') {
      var testUserId = null;
      var testUsername = 'icdtest' + (Date.now() % 100000);
      var testPassword = 'IcdT3st!Pw' + (Date.now() % 10000);

      await T.test('crud', 'admin', 'POST /admin/users (create)', async function () {
        var d = await T.apiPost('/admin/users', {
          username: testUsername,
          password: testPassword,
          email: testUsername + '@example.com',
          role: 'user'
        });
        T.assertShape(d, T.S.adminUser, 'admin-user');
        testUserId = d.id;
        T.registerCleanup(function () { if (testUserId) return T.safeDelete('/admin/users/' + testUserId); });
      });

      if (testUserId) {
        // Users start active (CreateUser sets IsActive=true).
        // Deactivate first, then test inactive login rejection.
        await T.test('crud', 'admin', 'PUT /admin/users/:id/active (deactivate)', async function () {
          var d = await T.apiPut('/admin/users/' + testUserId + '/active', { is_active: false });
          T.assert(typeof d === 'object', 'expected object');
        });

        await T.test('crud', 'admin', 'POST /auth/login (inactive user → reject)', async function () {
          var d = await T.publicPost('/auth/login', {
            login: testUsername,
            password: testPassword
          });
          T.assert(d._status === 401 || d._status === 403,
            'expected 401/403 for inactive user, got ' + d._status);
        });

        await T.test('crud', 'admin', 'PUT /admin/users/:id/active (activate)', async function () {
          var d = await T.apiPut('/admin/users/' + testUserId + '/active', { is_active: true });
          T.assert(typeof d === 'object', 'expected object');
        });

        var testUserToken = null;

        await T.test('crud', 'admin', 'POST /auth/login (active user → success)', async function () {
          var d = await T.publicPost('/auth/login', {
            login: testUsername,
            password: testPassword
          });
          T.assert(d._status === 200, 'expected 200, got ' + d._status +
            (d.error ? ' (' + d.error + ')' : ''));
          T.assertHasKey(d, 'access_token', 'login');
          T.assertHasKey(d, 'refresh_token', 'login');
          T.assertHasKey(d, 'user', 'login');
          T.assert(d.user.username === testUsername, 'username mismatch');
          testUserToken = d.access_token;
        });

        if (testUserToken) {
          await T.test('crud', 'admin', 'GET /profile (as test user)', async function () {
            var d = await T.authFetch(testUserToken, 'GET', '/profile');
            T.assertStatus(d, 200, 'profile');
            T.assert(d.username === testUsername, 'username mismatch');
          });

          await T.test('crud', 'admin', 'POST /auth/logout (test user)', async function () {
            var d = await T.publicPost('/auth/logout', { refresh_token: '' });
            T.assert(d._status === 200 || d._status === 401 || d._status === 204,
              'expected 200/204/401, got ' + d._status);
          });
        }

        await T.test('crud', 'admin', 'PUT /admin/users/:id/role (set admin)', async function () {
          var d = await T.apiPut('/admin/users/' + testUserId + '/role', { role: 'admin' });
          T.assert(typeof d === 'object', 'expected object');
        });

        await T.test('crud', 'admin', 'POST /admin/users/:id/reset-password', async function () {
          var d = await T.apiPost('/admin/users/' + testUserId + '/reset-password', {
            password: 'ResetPw!' + Date.now()
          });
          T.assert(typeof d === 'object', 'expected object');
          T.assert(!d.error, 'unexpected error: ' + (d.error || ''));
        });

        await T.test('crud', 'admin', 'POST /admin/users/:id/vault/reset', async function () {
          var d = await T.apiPost('/admin/users/' + testUserId + '/vault/reset', {});
          // May return 200 with message, or 400 if vault not configured
          T.assert(d._status === undefined || !d.error || d.error === 'vault not configured',
            'unexpected error: ' + (d.error || ''));
        });

        await T.test('crud', 'admin', 'DELETE /admin/users/:id', async function () {
          await T.safeDelete('/admin/users/' + testUserId);
          testUserId = null;
        });
      }

      // ── Admin Settings Roundtrip ──
      await T.test('crud', 'admin', 'PUT /admin/settings/:key (policy roundtrip)', async function () {
        // Read current value
        var before = await T.apiGet('/admin/settings/allow_registration');
        var originalVal = before.value;
        // Write a known value
        await T.apiPut('/admin/settings/allow_registration', { value: 'false' });
        var after = await T.apiGet('/admin/settings/allow_registration');
        T.assert(after.value === 'false', 'expected policy value "false"');
        // Restore
        if (originalVal !== undefined) {
          await T.apiPut('/admin/settings/allow_registration', { value: String(originalVal) });
        } else {
          await T.apiPut('/admin/settings/allow_registration', { value: 'true' });
        }
      });

      // ── Channel Purge ──
      await T.test('crud', 'admin', 'DELETE /admin/channels/:id/purge (lifecycle)', async function () {
        // Create a throwaway channel
        var ch = await T.apiPost('/channels', { title: 'icd-purge-test', type: 'direct' });
        T.assert(ch.id, 'expected channel id');
        // Archive it
        await T.apiPut('/channels/' + ch.id, { is_archived: true });
        // Purge rejects non-archived channel attempts — ours is archived, so purge should succeed
        var del = await T.apiDelete('/admin/channels/' + ch.id + '/purge');
        T.assert(del.ok === true, 'expected { ok: true }');
      });
    }

  };
})();
