/**
 * ICD Test Runner — CRUD: Personas
 * Admin persona lifecycle (create → list → update → tool grants →
 * KB bindings → delete), personal persona (policy-gated), team persona
 * (fixture team), persona groups CRUD.
 */
(function () {
  'use strict';
  var T = window.ICD;
  if (!T) return;
  if (!T.crud) T.crud = {};

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

    // ── Personas CRUD (admin + personal + team + tool grants + groups) ──
    var personaId = '';
    var personalPersonaId = '';
    var teamPersonaId = '';

    // Admin persona CRUD
    await T.test('crud', 'personas', 'POST /admin/personas (create global)', async function () {
      var d = await T.apiPost('/admin/personas', {
        name: 'ICD Test Persona', base_model_id: 'test-model',
        system_prompt: 'You are a test persona.', description: 'Created by ICD test runner'
      });
      T.assert(d.id, 'persona should have id');
      T.assert(d.scope === 'global', 'admin persona scope should be global');
      T.assert(d.handle, 'handle should be auto-generated');
      personaId = d.id;
    });

    if (personaId) {
      await T.test('crud', 'personas', 'GET /admin/personas (list contains new)', async function () {
        var d = await T.apiGet('/admin/personas');
        T.assertHasKey(d, 'data', '/admin/personas');
        var found = d.data.some(function (p) { return p.id === personaId; });
        T.assert(found, 'created persona should appear in admin list');
      });

      await T.test('crud', 'personas', 'PUT /admin/personas/:id (update)', async function () {
        var d = await T.apiPut('/admin/personas/' + personaId, { name: 'ICD Updated Persona' });
        T.assert(d.message === 'persona updated', 'expected update confirmation');
      });

      // Tool grants
      await T.test('crud', 'personas', 'GET /admin/personas/:id/tool-grants (empty)', async function () {
        var d = await T.apiGet('/admin/personas/' + personaId + '/tool-grants');
        T.assertHasKey(d, 'data', 'tool-grants');
        T.assert(Array.isArray(d.data), 'grants should be array');
        T.assert(d.data.length === 0, 'initial grants should be empty');
      });

      await T.test('crud', 'personas', 'PUT /admin/personas/:id/tool-grants (set)', async function () {
        var d = await T.apiPut('/admin/personas/' + personaId + '/tool-grants', {
          tool_names: ['web_search', 'calculator']
        });
        T.assert(d.status === 'ok', 'expected ok');
      });

      await T.test('crud', 'personas', 'GET /admin/personas/:id/tool-grants (verify)', async function () {
        var d = await T.apiGet('/admin/personas/' + personaId + '/tool-grants');
        T.assert(d.data.length === 2, 'should have 2 grants, got ' + d.data.length);
      });

      await T.test('crud', 'personas', 'PUT /admin/personas/:id/tool-grants (clear)', async function () {
        await T.apiPut('/admin/personas/' + personaId + '/tool-grants', { tool_names: [] });
        var d = await T.apiGet('/admin/personas/' + personaId + '/tool-grants');
        T.assert(d.data.length === 0, 'grants should be empty after clear');
      });

      // KB bindings
      await T.test('crud', 'personas', 'GET /admin/personas/:id/knowledge-bases (empty)', async function () {
        var d = await T.apiGet('/admin/personas/' + personaId + '/knowledge-bases');
        T.assertHasKey(d, 'data', 'persona-kbs');
        T.assert(Array.isArray(d.data), 'kbs should be array');
      });

      await T.test('crud', 'personas', 'DELETE /admin/personas/:id', async function () {
        await T.apiDelete('/admin/personas/' + personaId);
      });

      await T.test('crud', 'personas', 'GET /admin/personas (deleted gone)', async function () {
        var d = await T.apiGet('/admin/personas');
        var found = d.data.some(function (p) { return p.id === personaId; });
        T.assert(!found, 'deleted persona should not appear in list');
      });
    }

    // Personal persona (policy-gated)
    await T.test('crud', 'personas', 'POST /personas (create personal)', async function () {
      // Ensure policy allows personal personas
      try { await T.apiPut('/admin/settings/allow_user_personas', { value: 'true' }); } catch (e) { /* may already be set */ }
      var d = await T.apiPost('/personas', {
        name: 'ICD Personal Bot', base_model_id: 'test-model',
        system_prompt: 'Personal test.'
      });
      T.assert(d.id, 'personal persona should have id');
      T.assert(d.scope === 'personal', 'scope should be personal');
      personalPersonaId = d.id;
    });

    if (personalPersonaId) {
      await T.test('crud', 'personas', 'PUT /personas/:id (update personal)', async function () {
        var d = await T.apiPut('/personas/' + personalPersonaId, { description: 'updated desc' });
        T.assert(d.message === 'persona updated', 'expected update confirmation');
      });

      await T.test('crud', 'personas', 'GET /personas (list contains personal)', async function () {
        var d = await T.apiGet('/personas');
        T.assertHasKey(d, 'data', '/personas');
        var found = d.data.some(function (p) { return p.id === personalPersonaId; });
        T.assert(found, 'personal persona should appear in user list');
      });

      await T.test('crud', 'personas', 'DELETE /personas/:id (delete personal)', async function () {
        await T.apiDelete('/personas/' + personalPersonaId);
      });
    }

    // Team persona (uses fixture team)
    if (T.fixtures.team) {
      var tId = T.fixtures.team.id;

      await T.test('crud', 'personas', 'POST /teams/:teamId/personas (create)', async function () {
        var d = await T.apiPost('/teams/' + tId + '/personas', {
          name: 'ICD Team Bot', base_model_id: 'test-model',
          system_prompt: 'Team test.'
        });
        T.assert(d.id, 'team persona should have id');
        T.assert(d.scope === 'team', 'scope should be team');
        teamPersonaId = d.id;
      });

      if (teamPersonaId) {
        await T.test('crud', 'personas', 'PUT /teams/:teamId/personas/:id (update)', async function () {
          var d = await T.apiPut('/teams/' + tId + '/personas/' + teamPersonaId, { name: 'ICD Team Bot v2' });
          T.assert(d.message === 'persona updated', 'expected update confirmation');
        });

        await T.test('crud', 'personas', 'GET /teams/:teamId/personas/:id/tool-grants', async function () {
          var d = await T.apiGet('/teams/' + tId + '/personas/' + teamPersonaId + '/tool-grants');
          T.assertHasKey(d, 'data', 'team-tool-grants');
          T.assert(Array.isArray(d.data), 'grants should be array');
        });

        await T.test('crud', 'personas', 'PUT /teams/:teamId/personas/:id/tool-grants (set)', async function () {
          await T.apiPut('/teams/' + tId + '/personas/' + teamPersonaId + '/tool-grants', {
            tool_names: ['kb_search']
          });
          var d = await T.apiGet('/teams/' + tId + '/personas/' + teamPersonaId + '/tool-grants');
          T.assert(d.data.length === 1, 'team persona should have 1 grant');
        });

        await T.test('crud', 'personas', 'GET /teams/:teamId/personas/:id/knowledge-bases', async function () {
          var d = await T.apiGet('/teams/' + tId + '/personas/' + teamPersonaId + '/knowledge-bases');
          T.assertHasKey(d, 'data', 'team-persona-kbs');
        });

        await T.test('crud', 'personas', 'DELETE /teams/:teamId/personas/:id', async function () {
          await T.apiDelete('/teams/' + tId + '/personas/' + teamPersonaId);
        });

        await T.test('crud', 'personas', 'GET /teams/:teamId/personas (deleted gone)', async function () {
          var d = await T.apiGet('/teams/' + tId + '/personas');
          var found = d.data.some(function (p) { return p.id === teamPersonaId; });
          T.assert(!found, 'deleted team persona should not appear in list');
        });
      }
    }

    // Persona Groups CRUD
    var pgId = '';
    var pgMemberId = '';

    await T.test('crud', 'personas', 'POST /persona-groups (create)', async function () {
      var d = await T.apiPost('/persona-groups', { name: 'ICD Test Group', description: 'Test' });
      T.assert(d.id, 'group should have id');
      T.assert(d.scope === 'personal', 'group scope should be personal');
      pgId = d.id;
    });

    if (pgId) {
      await T.test('crud', 'personas', 'GET /persona-groups/:id (read)', async function () {
        var d = await T.apiGet('/persona-groups/' + pgId);
        T.assert(d.id === pgId, 'group id should match');
        T.assert(d.name === 'ICD Test Group', 'group name should match');
        T.assert(Array.isArray(d.members), 'members should be array');
      });

      await T.test('crud', 'personas', 'PUT /persona-groups/:id (update)', async function () {
        var d = await T.apiPut('/persona-groups/' + pgId, { name: 'ICD Updated Group' });
        T.assert(d.ok === true, 'expected ok');
      });

      await T.test('crud', 'personas', 'GET /persona-groups (list)', async function () {
        var d = await T.apiGet('/persona-groups');
        T.assertHasKey(d, 'data', '/persona-groups');
        var found = d.data.some(function (g) { return g.id === pgId; });
        T.assert(found, 'created group should appear in list');
      });

      // Add a member (need a persona — create a temporary one)
      var tmpPersonaId = '';
      await T.test('crud', 'personas', 'POST /admin/personas (for group member)', async function () {
        var d = await T.apiPost('/admin/personas', {
          name: 'Group Member Bot', base_model_id: 'test-model'
        });
        tmpPersonaId = d.id;
      });

      if (tmpPersonaId) {
        await T.test('crud', 'personas', 'POST /persona-groups/:id/members (add)', async function () {
          var d = await T.apiPost('/persona-groups/' + pgId + '/members', {
            persona_id: tmpPersonaId, is_leader: true
          });
          T.assert(d.ok === true, 'expected ok');
        });

        await T.test('crud', 'personas', 'GET /persona-groups/:id (with member)', async function () {
          var d = await T.apiGet('/persona-groups/' + pgId);
          T.assert(d.members.length === 1, 'should have 1 member');
          T.assert(d.members[0].is_leader === true, 'member should be leader');
          pgMemberId = d.members[0].id;
        });

        if (pgMemberId) {
          await T.test('crud', 'personas', 'DELETE /persona-groups/:id/members/:mid', async function () {
            await T.apiDelete('/persona-groups/' + pgId + '/members/' + pgMemberId);
          });

          await T.test('crud', 'personas', 'GET /persona-groups/:id (member removed)', async function () {
            var d = await T.apiGet('/persona-groups/' + pgId);
            T.assert(d.members.length === 0, 'should have 0 members after removal');
          });
        }

        // Cleanup temp persona
        try { await T.apiDelete('/admin/personas/' + tmpPersonaId); } catch (e) { /* ok */ }
      }

      await T.test('crud', 'personas', 'DELETE /persona-groups/:id', async function () {
        await T.apiDelete('/persona-groups/' + pgId);
      });
    }

  };
})();
