/**
 * SDK Test Runner — Fixtures
 *
 * Provisions reusable test resources before domains run and tears
 * them down afterward.  Modeled on the ICD test runner's fixture
 * pattern.
 *
 * Fixture resources (all optional — domains degrade gracefully):
 *
 *   providerConfig   Global API config created from the first admin
 *                    config that has at least one embedding model.
 *                    Enables: knowledge.search, model preference tests.
 *
 *   embeddingModel   {model_id, provider_config_id} picked from the
 *                    enabled models list after the config is created.
 *
 *   policies         Policy toggles applied at setup, reverted at
 *                    teardown (e.g. allow_user_personas).
 *
 *   team             Test team (with current user as admin).
 *
 * Access: window.SDKR.fixtures.*
 */
(function () {
  'use strict';
  var T = window.SDKR;
  if (!T) return;

  T.fixtures = {
    ready:          false,
    providerConfig: null,   // { id, name, provider }
    embeddingModel: null,   // { model_id, provider_config_id }
    team:           null,   // { id, name }
    policies:       {},     // key → original value (for revert)
    errors:         []
  };

  // ─── Policy helpers ──────────────────────────────────────

  async function setPolicy(key, value) {
    var fix = T.fixtures;
    try {
      // Save original for revert
      if (!(key in fix.policies)) {
        try {
          var settings = await T.raw.get('/admin/settings');
          fix.policies[key] = settings.policies?.[key] ?? null;
        } catch (_) {
          fix.policies[key] = null;
        }
      }
      await T.raw.put('/admin/settings/' + key, { value: String(value) });
    } catch (e) {
      fix.errors.push('policy ' + key + ': ' + e.message);
    }
  }

  async function revertPolicies() {
    var fix = T.fixtures;
    var keys = Object.keys(fix.policies);
    for (var i = 0; i < keys.length; i++) {
      var val = fix.policies[keys[i]];
      try {
        await T.raw.put('/admin/settings/' + keys[i], {
          value: val === null ? 'false' : String(val)
        });
      } catch (_) { /* best effort */ }
    }
  }

  // ─── Provider / model discovery ──────────────────────────

  async function provisionProvider() {
    var fix = T.fixtures;

    // ── Read UI inputs (provider + API key) ──
    var ui = T._fixtureInput || {};
    var selectedProvider = ui.provSelect ? ui.provSelect.value : '';
    var apiKey = ui.keyInput ? ui.keyInput.value.trim() : '';
    var statusEl = ui.statusEl;

    function setStatus(msg) {
      if (statusEl) statusEl.textContent = msg;
      console.log('[SDKR:fixtures] ' + msg);
    }

    // ── Resolve default endpoint for selected provider ──
    var defaultEndpoint = '';
    if (selectedProvider) {
      try {
        var typesResp = await T.raw.get('/admin/provider-types');
        var types = typesResp.types || typesResp.data || typesResp || [];
        var match = types.find ? types.find(function (t) { return t.id === selectedProvider; }) : null;
        if (match) defaultEndpoint = match.default_endpoint || '';
      } catch (_) { /* best effort — endpoint will be required in payload */ }
    }

    // Check if any configs already exist
    try {
      var configs = await T.raw.get('/admin/configs');
      var list = configs.data || configs.configs || [];
      if (list.length > 0) {
        fix.providerConfig = { id: list[0].id, name: list[0].name, provider: list[0].provider };
        setStatus('Using existing config: ' + list[0].name);
      }
    } catch (e) {
      fix.errors.push('config list: ' + e.message);
      return;
    }

    // If no config exists and user provided a provider + key, create one
    if (!fix.providerConfig && selectedProvider && apiKey) {
      try {
        var configData = {
          name: 'sdkr-fixture-' + selectedProvider,
          provider: selectedProvider,
          endpoint: defaultEndpoint,
          api_key: apiKey,
          scope: 'global'
        };
        setStatus('Creating ' + selectedProvider + ' config...');
        var created = await T.raw.post('/admin/configs', configData);
        if (created && created.id) {
          fix.providerConfig = { id: created.id, name: configData.name, provider: selectedProvider };
          fix._createdConfig = true;  // mark for cleanup
          setStatus('Config created: ' + configData.name);
          T.registerCleanup(function () {
            if (fix._createdConfig && fix.providerConfig) {
              return T.safeDelete('/admin/configs/' + fix.providerConfig.id);
            }
          });
        }
      } catch (e) {
        setStatus('Config create failed: ' + e.message);
        fix.errors.push('config create: ' + e.message);
      }
    } else if (!fix.providerConfig && selectedProvider && !apiKey) {
      // Provider selected but no key — try creating without key (some providers
      // use server-side keys configured via env vars)
      try {
        var configData2 = {
          name: 'sdkr-fixture-' + selectedProvider,
          provider: selectedProvider,
          endpoint: defaultEndpoint,
          scope: 'global'
        };
        var created2 = await T.raw.post('/admin/configs', configData2);
        if (created2 && created2.id) {
          fix.providerConfig = { id: created2.id, name: configData2.name, provider: selectedProvider };
          fix._createdConfig = true;
          setStatus('Config created (server key): ' + configData2.name);
          T.registerCleanup(function () {
            if (fix._createdConfig && fix.providerConfig) {
              return T.safeDelete('/admin/configs/' + fix.providerConfig.id);
            }
          });
        }
      } catch (_) {
        setStatus('No config — skipping model tests');
      }
    } else if (!fix.providerConfig) {
      setStatus('No provider selected — model tests will be skipped');
    }

    // Fetch models if we have a config
    if (fix.providerConfig) {
      try {
        await T.raw.post('/admin/models/fetch', {});
        // Wait briefly for async model fetch
        await new Promise(function (r) { setTimeout(r, 1500); });
      } catch (_) { /* fetch may fail if no key */ }

      // Look for an embedding model
      try {
        var models = await T.raw.get('/models/enabled');
        var list2 = models.data || [];
        for (var m = 0; m < list2.length; m++) {
          var caps = list2[m].capabilities || {};
          if (caps.embedding || list2[m].model_type === 'embedding') {
            fix.embeddingModel = {
              model_id: list2[m].model_id,
              provider_config_id: list2[m].provider_config_id
            };
            console.log('[SDKR:fixtures] Embedding model: ' + list2[m].model_id);
            break;
          }
        }
      } catch (_) { /* no models available */ }
    }
  }

  // ─── Team ────────────────────────────────────────────────

  async function provisionTeam() {
    var fix = T.fixtures;
    try {
      var team = await T.raw.post('/admin/teams', {
        name: 'sdkr-fixture-' + Date.now(),
        description: 'SDK test runner fixture team'
      });
      if (team && team.id) {
        fix.team = { id: team.id, name: team.name };
        T.registerCleanup(function () {
          if (fix.team) return T.safeDelete('/admin/teams/' + fix.team.id);
        });
      }
    } catch (e) {
      fix.errors.push('team: ' + e.message);
    }
  }

  // ─── Provision / Teardown ────────────────────────────────

  T.provisionFixtures = async function () {
    var fix = T.fixtures;
    if (fix.ready) return;

    console.log('[SDKR:fixtures] Provisioning...');

    // Policies
    await setPolicy('allow_user_personas', 'true');

    // Provider + models
    await provisionProvider();

    // Team
    await provisionTeam();

    fix.ready = true;

    if (fix.errors.length > 0) {
      console.warn('[SDKR:fixtures] ' + fix.errors.length + ' errors:', fix.errors);
    }
    console.log('[SDKR:fixtures] Ready —',
      'config:', fix.providerConfig ? fix.providerConfig.name : 'none',
      '| embedding:', fix.embeddingModel ? fix.embeddingModel.model_id : 'none',
      '| team:', fix.team ? fix.team.name : 'none'
    );
  };

  T.teardownFixtures = async function () {
    await revertPolicies();
    // Cleanup functions registered via T.registerCleanup handle
    // the config + team deletion.
    T.fixtures = {
      ready: false, providerConfig: null, embeddingModel: null,
      team: null, policies: {}, errors: []
    };
    console.log('[SDKR:fixtures] Torn down');
  };

})();
