const { describe, it, beforeEach, afterEach } = require('node:test');
const assert = require('node:assert/strict');
const { resolveStrategy, getStrategyNames, STRATEGIES } = require('../src/gep/strategy');

describe('STRATEGIES', function () {
  it('defines all expected presets', function () {
    const names = getStrategyNames();
    assert.ok(names.includes('balanced'));
    assert.ok(names.includes('innovate'));
    assert.ok(names.includes('harden'));
    assert.ok(names.includes('repair-only'));
    assert.ok(names.includes('early-stabilize'));
    assert.ok(names.includes('steady-state'));
  });

  it('all strategies have required fields', function () {
    for (const [name, s] of Object.entries(STRATEGIES)) {
      assert.equal(typeof s.repair, 'number', `${name}.repair`);
      assert.equal(typeof s.optimize, 'number', `${name}.optimize`);
      assert.equal(typeof s.innovate, 'number', `${name}.innovate`);
      assert.equal(typeof s.repairLoopThreshold, 'number', `${name}.repairLoopThreshold`);
      assert.equal(typeof s.label, 'string', `${name}.label`);
      assert.equal(typeof s.description, 'string', `${name}.description`);
    }
  });

  it('all strategy ratios sum to approximately 1.0', function () {
    for (const [name, s] of Object.entries(STRATEGIES)) {
      const sum = s.repair + s.optimize + s.innovate + (s.explore || 0);
      assert.ok(Math.abs(sum - 1.0) < 0.01, `${name} ratios sum to ${sum}`);
    }
  });
});

describe('resolveStrategy', function () {
  let origStrategy;
  let origForceInnovation;
  let origEvolveForceInnovation;

  beforeEach(function () {
    origStrategy = process.env.EVOLVE_STRATEGY;
    origForceInnovation = process.env.FORCE_INNOVATION;
    origEvolveForceInnovation = process.env.EVOLVE_FORCE_INNOVATION;
    delete process.env.EVOLVE_STRATEGY;
    delete process.env.FORCE_INNOVATION;
    delete process.env.EVOLVE_FORCE_INNOVATION;
  });

  afterEach(function () {
    if (origStrategy !== undefined) process.env.EVOLVE_STRATEGY = origStrategy;
    else delete process.env.EVOLVE_STRATEGY;
    if (origForceInnovation !== undefined) process.env.FORCE_INNOVATION = origForceInnovation;
    else delete process.env.FORCE_INNOVATION;
    if (origEvolveForceInnovation !== undefined) process.env.EVOLVE_FORCE_INNOVATION = origEvolveForceInnovation;
    else delete process.env.EVOLVE_FORCE_INNOVATION;
  });

  it('defaults to balanced when no env var set', function () {
    const s = resolveStrategy({});
    assert.ok(['balanced', 'early-stabilize'].includes(s.name));
  });

  it('respects explicit EVOLVE_STRATEGY', function () {
    process.env.EVOLVE_STRATEGY = 'harden';
    const s = resolveStrategy({});
    assert.equal(s.name, 'harden');
    assert.equal(s.label, 'Hardening');
  });

  it('respects innovate strategy', function () {
    process.env.EVOLVE_STRATEGY = 'innovate';
    const s = resolveStrategy({});
    assert.equal(s.name, 'innovate');
    assert.ok(s.innovate >= 0.8);
  });

  it('respects repair-only strategy', function () {
    process.env.EVOLVE_STRATEGY = 'repair-only';
    const s = resolveStrategy({});
    assert.equal(s.name, 'repair-only');
    assert.equal(s.innovate, 0);
  });

  it('FORCE_INNOVATION=true maps to innovate', function () {
    process.env.FORCE_INNOVATION = 'true';
    const s = resolveStrategy({});
    assert.equal(s.name, 'innovate');
  });

  it('EVOLVE_FORCE_INNOVATION=true maps to innovate', function () {
    process.env.EVOLVE_FORCE_INNOVATION = 'true';
    const s = resolveStrategy({});
    assert.equal(s.name, 'innovate');
  });

  it('explicit EVOLVE_STRATEGY takes precedence over FORCE_INNOVATION', function () {
    process.env.EVOLVE_STRATEGY = 'harden';
    process.env.FORCE_INNOVATION = 'true';
    const s = resolveStrategy({});
    assert.equal(s.name, 'harden');
  });

  it('saturation signal triggers steady-state', function () {
    const s = resolveStrategy({ signals: ['evolution_saturation'] });
    assert.equal(s.name, 'steady-state');
  });

  it('force_steady_state signal triggers steady-state', function () {
    const s = resolveStrategy({ signals: ['force_steady_state'] });
    assert.equal(s.name, 'steady-state');
  });

  it('falls back to balanced for unknown strategy name', function () {
    process.env.EVOLVE_STRATEGY = 'nonexistent';
    const s = resolveStrategy({});
    const fallback = STRATEGIES['balanced'];
    assert.equal(s.repair, fallback.repair);
    assert.equal(s.optimize, fallback.optimize);
    assert.equal(s.innovate, fallback.innovate);
  });

  it('auto maps to balanced or heuristic', function () {
    process.env.EVOLVE_STRATEGY = 'auto';
    const s = resolveStrategy({});
    assert.ok(['balanced', 'early-stabilize'].includes(s.name));
  });

  it('returned strategy has name property', function () {
    process.env.EVOLVE_STRATEGY = 'harden';
    const s = resolveStrategy({});
    assert.equal(s.name, 'harden');
  });
});
