/**
 * ICD Test Runner — CRUD: Extensions
 * Extension install lifecycle (install → list → update → user list →
 * tier filter → manifest → tools → assets → settings → disable →
 * duplicate 409 → invalid tier 400 → not found 404 → disabled asset 404 →
 * delete), system extension disable rejection.
 */
(function () {
  'use strict';
  var T = window.ICD;
  if (!T) return;
  if (!T.crud) T.crud = {};

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

    // ── Extensions CRUD ──

    var extId = null;       // UUID (DB id)
    var extExtId = null;    // ext_id (manifest id)

    await T.test('crud', 'extensions', 'POST /admin/extensions (install)', async function () {
      extExtId = testTag + '-ext';
      var d = await T.apiPost('/admin/extensions', {
        ext_id: extExtId,
        name: testTag + ' Test Extension',
        version: '1.0.0',
        tier: 'browser',
        description: 'ICD CRUD test extension',
        author: 'icd-runner',
        manifest: { _script: 'console.log("icd-test");', tools: [{ name: 'icd_tool', description: 'Test tool' }] },
        is_enabled: true,
        is_system: false
      });
      T.assertHasKey(d, 'data', 'install response');
      T.assertShape(d.data, T.S.extension, 'installed extension');
      
      T.assert(d.data.tier === 'browser', 'tier should be browser');
      T.assert(d.data.enabled === true, 'should be enabled');
      T.assert(d.data.is_system === false, 'should not be system');
      extId = d.data.id;
      T.registerCleanup(function () { if (extId) return T.safeDelete('/admin/extensions/' + extId); });
    });

    if (extId) {
      await T.test('crud', 'extensions', 'GET /admin/extensions (list)', async function () {
        var d = await T.apiGet('/admin/extensions');
        T.assertHasKey(d, 'data', '/admin/extensions');
        T.assert(Array.isArray(d.data), 'admin list should be array');
        var found = d.data.some(function (e) { return e.id === extId; });
        T.assert(found, 'installed extension should be in admin list');
      });

      await T.test('crud', 'extensions', 'PUT /admin/extensions/:id (update)', async function () {
        var d = await T.apiPut('/admin/extensions/' + extId, {
          name: testTag + ' Updated Extension',
          version: '2.0.0',
          description: 'Updated description'
        });
        T.assertHasKey(d, 'data', 'update response');
        T.assert(d.data.title === testTag + ' Updated Extension', 'name not updated');
        T.assert(d.data.version === '2.0.0', 'version not updated');
      });

      await T.test('crud', 'extensions', 'GET /extensions (user list)', async function () {
        var d = await T.apiGet('/extensions');
        T.assertHasKey(d, 'data', '/extensions');
        T.assert(Array.isArray(d.data), 'user list should be array');
        var found = d.data.some(function (e) { return e.id === extId; });
        T.assert(found, 'enabled extension should appear in user list');
      });

      await T.test('crud', 'extensions', 'GET /extensions?tier=browser (filter)', async function () {
        var d = await T.apiGet('/extensions?tier=browser');
        T.assertHasKey(d, 'data', '/extensions?tier=browser');
        var found = d.data.some(function (e) { return e.id === extId; });
        T.assert(found, 'browser extension should appear with tier filter');
      });

      await T.test('crud', 'extensions', 'GET /extensions?tier=starlark (filter excludes)', async function () {
        var d = await T.apiGet('/extensions?tier=starlark');
        T.assertHasKey(d, 'data', '/extensions?tier=starlark');
        var found = d.data.some(function (e) { return e.id === extId; });
        T.assert(!found, 'browser extension should NOT appear with starlark filter');
      });

      await T.test('crud', 'extensions', 'GET /extensions/:id/manifest (by ext_id)', async function () {
        var d = await T.apiGet('/extensions/' + extExtId + '/manifest');
        T.assertHasKey(d, 'data', 'manifest response');
        T.assert(typeof d.data === 'object', 'manifest should be object');
      });

      await T.test('crud', 'extensions', 'GET /extensions/tools (tool schemas)', async function () {
        var d = await T.apiGet('/extensions/tools');
        T.assertHasKey(d, 'data', '/extensions/tools');
        T.assert(Array.isArray(d.data), 'tools should be array');
        var found = d.data.some(function (t) { return t.name === 'icd_tool'; });
        T.assert(found, 'icd_tool should appear in tool schemas');
      });

      await T.test('crud', 'extensions', 'GET /extensions/:id/assets (public, no auth)', async function () {
        var resp = await fetch(T.base + '/api/v1/extensions/' + extExtId + '/assets/main.js');
        T.assert(resp.ok, 'asset fetch should succeed: ' + resp.status);
        var text = await resp.text();
        T.assert(text.indexOf('icd-test') !== -1, 'script body should contain icd-test');
        var ct = resp.headers.get('Content-Type') || '';
        T.assert(ct.indexOf('javascript') !== -1, 'content-type should be javascript, got ' + ct);
      });

      await T.test('crud', 'extensions', 'POST /extensions/:id/settings (save)', async function () {
        var d = await T.apiPost('/extensions/' + extId + '/settings', {
          settings: { theme: 'dark' },
          is_enabled: true
        });
        T.assertHasKey(d, 'ok', 'settings response');
        T.assert(d.ok === true, 'ok should be true');
      });

      await T.test('crud', 'extensions', 'POST /extensions/:id/settings (disable non-system)', async function () {
        var d = await T.apiPost('/extensions/' + extId + '/settings', { is_enabled: false });
        T.assert(d.ok === true, 'should succeed for non-system extension');
        // Re-enable for subsequent tests
        await T.apiPost('/extensions/' + extId + '/settings', { is_enabled: true });
      });

      await T.test('crud', 'extensions', 'POST /admin/extensions (duplicate → 409)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'POST', '/admin/extensions', {
          ext_id: extExtId, name: 'Duplicate'
        });
        T.assert(d._status === 409, 'duplicate ext_id should return 409, got ' + d._status);
      });

      await T.test('crud', 'extensions', 'POST /admin/extensions (invalid tier → 400)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'POST', '/admin/extensions', {
          ext_id: 'bad-tier-ext', name: 'Bad Tier', tier: 'invalid'
        });
        T.assert(d._status === 400, 'invalid tier should return 400, got ' + d._status);
      });

      await T.test('crud', 'extensions', 'PUT /admin/extensions/:id (not found → 404)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'PUT',
          '/admin/extensions/00000000-0000-0000-0000-000000000000', { name: 'ghost' });
        T.assert(d._status === 404, 'nonexistent should return 404, got ' + d._status);
      });

      await T.test('crud', 'extensions', 'GET /extensions/:id/assets (disabled → 404)', async function () {
        // Disable via admin
        await T.apiPut('/admin/extensions/' + extId, { is_enabled: false });
        // Cache-bust: the earlier asset fetch is cached (max-age=3600)
        var resp = await fetch(T.base + '/api/v1/extensions/' + extExtId + '/assets/main.js?_cb=' + Date.now());
        T.assert(resp.status === 404, 'disabled asset should 404, got ' + resp.status);
        // Re-enable
        await T.apiPut('/admin/extensions/' + extId, { is_enabled: true });
      });

      await T.test('crud', 'extensions', 'DELETE /admin/extensions/:id', async function () {
        await T.safeDelete('/admin/extensions/' + extId);
        // Verify gone from admin list
        var d = await T.apiGet('/admin/extensions');
        var found = d.data.some(function (e) { return e.id === extId; });
        T.assert(!found, 'deleted extension should not appear in list');
        extId = null;
      });
    }

    // ── System extension disable rejection ──

    var sysExtId = null;
    await T.test('crud', 'extensions', 'POST /admin/extensions (system ext)', async function () {
      var d = await T.apiPost('/admin/extensions', {
        ext_id: testTag + '-sys-ext', name: 'System Test', is_system: true, is_enabled: true
      });
      T.assertHasKey(d, 'data', 'system install');
      T.assert(d.data.is_system === true, 'should be system');
      sysExtId = d.data.id;
      T.registerCleanup(function () { if (sysExtId) return T.safeDelete('/admin/extensions/' + sysExtId); });
    });

    if (sysExtId) {
      await T.test('crud', 'extensions', 'POST /extensions/:id/settings (system disable → 403)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'POST',
          '/extensions/' + sysExtId + '/settings', { is_enabled: false });
        T.assert(d._status === 403, 'disabling system ext should return 403, got ' + d._status);
      });

      await T.test('crud', 'extensions', 'DELETE /admin/extensions/:id (system cleanup)', async function () {
        await T.safeDelete('/admin/extensions/' + sysExtId);
        sysExtId = null;
      });
    }

  };
})();
