// Basic unit tests for BasinGeometry.
// Run with:  node --test test/basic/BasinGeometry.basic.test.js

const test = require('node:test');
const assert = require('node:assert/strict');

const BasinGeometry = require('../../src/basin/BasinGeometry');

function makeBasin(overrides = {}) {
  const basin = {
    volume: 50,
    height: 5,
    inflowLevel: 3,
    outflowLevel: 0.2,
    overflowLevel: 4.5,
    ...overrides.basin,
  };
  const hydraulics = {
    minHeightBasedOn: 'outlet',
    ...overrides.hydraulics,
  };
  return new BasinGeometry(basin, hydraulics);
}

test('constructor produces correct surfaceArea = volume / height', () => {
  const g = makeBasin();
  assert.equal(g.surfaceArea, 10);  // 50 / 5
  assert.equal(g.heightBasin, 5);
  assert.equal(g.volEmptyBasin, 50);
});

test('maxVolAtOverflow equals overflowLevel × surfaceArea', () => {
  const g = makeBasin();
  assert.equal(g.maxVolAtOverflow, 4.5 * 10);  // 45
  assert.equal(g.minVolAtInflow, 3 * 10);       // 30
  assert.equal(g.minVolAtOutflow, 0.2 * 10);    // 2
  assert.equal(g.maxVol, 50);
});

test("minVol selects outlet-based when minHeightBasedOn = 'outlet'", () => {
  const g = makeBasin();
  assert.equal(g.minVol, g.minVolAtOutflow);
  assert.equal(g.minHeightBasedOn, 'outlet');
});

test("minVol selects inlet-based when minHeightBasedOn = 'inlet'", () => {
  const g = makeBasin({ hydraulics: { minHeightBasedOn: 'inlet' } });
  assert.equal(g.minVol, g.minVolAtInflow);
  assert.equal(g.minHeightBasedOn, 'inlet');
});

test('volumeFromLevel(0) returns 0; negative level clamps to 0', () => {
  const g = makeBasin();
  assert.equal(g.volumeFromLevel(0), 0);
  assert.equal(g.volumeFromLevel(-1), 0);
  assert.equal(g.volumeFromLevel(-1e9), 0);
});

test('volumeFromLevel(positive) is level × surfaceArea', () => {
  const g = makeBasin();
  assert.equal(g.volumeFromLevel(2.5), 25);
  assert.equal(g.volumeFromLevel(5), 50);
});

test('levelFromVolume(maxVol) returns heightBasin', () => {
  const g = makeBasin();
  assert.equal(g.levelFromVolume(g.maxVol), g.heightBasin);
});

test('levelFromVolume(0) returns 0; negative volume clamps to 0', () => {
  const g = makeBasin();
  assert.equal(g.levelFromVolume(0), 0);
  assert.equal(g.levelFromVolume(-10), 0);
});

test('round-trip: volumeFromLevel(levelFromVolume(v)) ≈ v for v in range', () => {
  const g = makeBasin();
  for (const v of [0, 0.001, 1, 12.34, 25, 49.999, 50]) {
    const back = g.volumeFromLevel(g.levelFromVolume(v));
    assert.ok(Math.abs(back - v) < 1e-9, `round-trip failed for v=${v}, got ${back}`);
  }
});

test('round-trip: levelFromVolume(volumeFromLevel(L)) ≈ L for L in range', () => {
  const g = makeBasin();
  for (const L of [0, 0.05, 1, 2.5, 4.5, 5]) {
    const back = g.levelFromVolume(g.volumeFromLevel(L));
    assert.ok(Math.abs(back - L) < 1e-9, `round-trip failed for L=${L}, got ${back}`);
  }
});

test('snapshot() exposes legacy this.basin field names', () => {
  const g = makeBasin();
  const s = g.snapshot();
  const expectedKeys = [
    'volEmptyBasin', 'heightBasin', 'inflowLevel', 'outflowLevel',
    'overflowLevel', 'surfaceArea', 'maxVol', 'maxVolAtOverflow',
    'minVolAtInflow', 'minVolAtOutflow', 'minVol', 'minHeightBasedOn',
  ];
  for (const k of expectedKeys) {
    assert.ok(k in s, `snapshot missing key: ${k}`);
  }
  assert.equal(s.volEmptyBasin, 50);
  assert.equal(s.surfaceArea, 10);
  assert.equal(s.minHeightBasedOn, 'outlet');
});
