/**
 * ICD Test Runner — CRUD: Surfaces
 * Surface install lifecycle (install → read → admin list → user list →
 * disable → hidden from user → still in admin → enable → visible again →
 * core disable rejection → not found → disable not found → missing manifest →
 * core conflict → reseed preserves enabled → delete → delete not found).
 * Uses T.crud.buildTestZip() from _helpers.js.
 */
(function () {
  'use strict';
  var T = window.ICD;
  if (!T) return;
  if (!T.crud) T.crud = {};

  var buildTestZip = T.crud.buildTestZip;

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

    // ── Surfaces CRUD ──

    var surfaceId = null;

    await T.test('crud', 'surfaces', 'POST /admin/surfaces/install (happy path)', async function () {
      surfaceId = 'icd-test-' + Date.now();
      var manifest = JSON.stringify({
        id: surfaceId,
        title: 'ICD Test Surface',
        route: '/s/' + surfaceId
      });
      var zipBlob = buildTestZip({ 'manifest.json': manifest });
      await T.apiUpload('/admin/surfaces/install', zipBlob, surfaceId + '.surface');

      // Verify it exists
      var d = await T.apiGet('/admin/surfaces/' + surfaceId);
      T.assert(d.id === surfaceId, 'installed surface id mismatch');
      T.assert(d.title === 'ICD Test Surface', 'title mismatch');
      T.registerCleanup(async function () {
        if (surfaceId) {
          var token = await T.getAuthToken();
          return T.authFetch(token, 'DELETE', '/admin/surfaces/' + surfaceId);
        }
      });
    });

    if (surfaceId) {
      await T.test('crud', 'surfaces', 'GET /admin/surfaces/:id (read)', async function () {
        var d = await T.apiGet('/admin/surfaces/' + surfaceId);
        T.assertShape(d, T.S.surfaceAdmin, 'surface detail');
        T.assert(d.id === surfaceId, 'id mismatch');
        T.assert(d.source === 'extension', 'source should be extension');
        T.assert(d.enabled === true, 'newly installed surface should be enabled');
      });

      await T.test('crud', 'surfaces', 'GET /admin/surfaces (list includes new)', async function () {
        var d = await T.apiGet('/admin/surfaces');
        T.assertHasKey(d, 'data', '/admin/surfaces');
        var found = d.data.some(function (s) { return s.id === surfaceId; });
        T.assert(found, 'installed surface should appear in admin list');
      });

      await T.test('crud', 'surfaces', 'GET /surfaces (user list includes new)', async function () {
        var d = await T.apiGet('/surfaces');
        T.assertHasKey(d, 'data', '/surfaces');
        var found = d.data.some(function (s) { return s.id === surfaceId; });
        T.assert(found, 'enabled extension surface should appear in user nav list');
        // Verify nav shape: id + title + route, NOT source/enabled
        var entry = d.data.find(function (s) { return s.id === surfaceId; });
        T.assert(entry.route !== undefined, 'nav entry should have route');
        T.assert(entry.source === undefined, 'nav entry should NOT have source');
        T.assert(entry.enabled === undefined, 'nav entry should NOT have enabled');
      });

      await T.test('crud', 'surfaces', 'PUT /admin/surfaces/:id/disable', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'PUT',
          '/admin/surfaces/' + surfaceId + '/disable');
        T.assertStatus(d, 200, 'disable');
        T.assert(d.enabled === false, 'should report disabled');
      });

      await T.test('crud', 'surfaces', 'GET /surfaces (disabled hidden from user)', async function () {
        var d = await T.apiGet('/surfaces');
        var found = d.data.some(function (s) { return s.id === surfaceId; });
        T.assert(!found, 'disabled surface should NOT appear in user nav list');
      });

      await T.test('crud', 'surfaces', 'GET /admin/surfaces (disabled still in admin)', async function () {
        var d = await T.apiGet('/admin/surfaces');
        var entry = d.data.find(function (s) { return s.id === surfaceId; });
        T.assert(entry, 'disabled surface should still appear in admin list');
        T.assert(entry.enabled === false, 'should show as disabled in admin list');
      });

      await T.test('crud', 'surfaces', 'PUT /admin/surfaces/:id/enable', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'PUT',
          '/admin/surfaces/' + surfaceId + '/enable');
        T.assertStatus(d, 200, 'enable');
        T.assert(d.enabled === true, 'should report enabled');
      });

      await T.test('crud', 'surfaces', 'GET /surfaces (re-enabled visible)', async function () {
        var d = await T.apiGet('/surfaces');
        var found = d.data.some(function (s) { return s.id === surfaceId; });
        T.assert(found, 're-enabled surface should appear in user nav list');
      });

      await T.test('crud', 'surfaces', 'PUT /admin/surfaces/chat/disable (reject → 400)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'PUT',
          '/admin/surfaces/chat/disable');
        T.assert(d._status === 400, 'disabling chat should return 400, got ' + d._status);
      });

      await T.test('crud', 'surfaces', 'PUT /admin/surfaces/admin/disable (reject → 400)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'PUT',
          '/admin/surfaces/admin/disable');
        T.assert(d._status === 400, 'disabling admin should return 400, got ' + d._status);
      });

      await T.test('crud', 'surfaces', 'DELETE /admin/surfaces/chat (core reject → 400)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'DELETE',
          '/admin/surfaces/chat');
        T.assert(d._status === 400, 'deleting core surface should return 400, got ' + d._status);
      });

      await T.test('crud', 'surfaces', 'GET /admin/surfaces/:id (not found → 404)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'GET',
          '/admin/surfaces/nonexistent-surface-id');
        T.assert(d._status === 404, 'nonexistent should return 404, got ' + d._status);
      });

      await T.test('crud', 'surfaces', 'PUT /admin/surfaces/nonexistent/disable (404)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'PUT',
          '/admin/surfaces/nonexistent-surface-id/disable');
        T.assert(d._status === 404, 'disable nonexistent should return 404, got ' + d._status);
      });

      await T.test('crud', 'surfaces', 'POST /admin/surfaces/install (missing manifest → 400)', async function () {
        var zipBlob = buildTestZip({ 'readme.txt': 'no manifest here' });
        var d;
        try {
          d = await T.apiUpload('/admin/surfaces/install', zipBlob, 'bad.surface');
          T.assert(false, 'should have thrown');
        } catch (e) {
          T.assert(e.message.indexOf('400') !== -1, 'missing manifest should 400: ' + e.message);
        }
      });

      await T.test('crud', 'surfaces', 'POST /admin/surfaces/install (core conflict → 409)', async function () {
        var manifest = JSON.stringify({ id: 'chat', title: 'Evil Chat', route: '/s/chat' });
        var zipBlob = buildTestZip({ 'manifest.json': manifest });
        var d;
        try {
          d = await T.apiUpload('/admin/surfaces/install', zipBlob, 'chat.surface');
          // If no throw, check status manually
          T.assert(false, 'overwriting core surface should have thrown');
        } catch (e) {
          T.assert(e.message.indexOf('409') !== -1, 'core conflict should 409: ' + e.message);
        }
      });

      await T.test('crud', 'surfaces', 'POST /admin/surfaces/install (reseed preserves enabled)', async function () {
        // Surface was re-enabled above. Disable it, then re-install.
        await T.authFetch(await T.getAuthToken(), 'PUT',
          '/admin/surfaces/' + surfaceId + '/disable');

        // Re-install same ID
        var manifest = JSON.stringify({
          id: surfaceId,
          title: 'ICD Test Surface v2',
          route: '/s/' + surfaceId
        });
        var zipBlob = buildTestZip({ 'manifest.json': manifest });
        await T.apiUpload('/admin/surfaces/install', zipBlob, surfaceId + '.surface');

        // Verify title updated but enabled preserved as false
        var d = await T.apiGet('/admin/surfaces/' + surfaceId);
        T.assert(d.title === 'ICD Test Surface v2', 'title should be updated after reseed');
        T.assert(d.enabled === false, 'enabled should be preserved as false after reseed');

        // Re-enable for cleanup
        await T.authFetch(await T.getAuthToken(), 'PUT',
          '/admin/surfaces/' + surfaceId + '/enable');
      });

      await T.test('crud', 'surfaces', 'DELETE /admin/surfaces/:id', async function () {
        var token = await T.getAuthToken();
        var d = await T.authFetch(token, 'DELETE', '/admin/surfaces/' + surfaceId);
        T.assertStatus(d, 200, 'delete');
        T.assert(d.deleted === true, 'should report deleted');

        // Verify gone
        var check = await T.authFetch(token, 'GET', '/admin/surfaces/' + surfaceId);
        T.assert(check._status === 404, 'deleted surface should 404 on get');
        surfaceId = null;
      });

      await T.test('crud', 'surfaces', 'DELETE /admin/surfaces/nonexistent (404)', async function () {
        var d = await T.authFetch(await T.getAuthToken(), 'DELETE',
          '/admin/surfaces/nonexistent-surface-id');
        T.assert(d._status === 404, 'delete nonexistent should return 404, got ' + d._status);
      });
    }

  };
})();
