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

const ErrorMetrics = require('../src/nrmse/errorMetrics.js');
const { makeLogger } = require('./helpers.js');

test('MSE and RMSE calculations are correct', () => {
  const m = new ErrorMetrics({}, makeLogger());
  const predicted = [1, 2, 3];
  const measured = [1, 3, 5];

  assert.ok(Math.abs(m.meanSquaredError(predicted, measured) - 5 / 3) < 1e-9);
  assert.ok(Math.abs(m.rootMeanSquaredError(predicted, measured) - Math.sqrt(5 / 3)) < 1e-9);
});

test('MSE throws for mismatched series lengths in strict mode', () => {
  const m = new ErrorMetrics({}, makeLogger());
  assert.throws(() => m.meanSquaredError([1, 2], [1]), /same length/);
});

test('normalizeUsingRealtime throws when range is zero', () => {
  const m = new ErrorMetrics({}, makeLogger());
  assert.throws(() => m.normalizeUsingRealtime([1, 1, 1], [1, 1, 1]), /Invalid process range/);
});

test('longTermNRMSD returns 0 before 100 samples and value after', () => {
  const m = new ErrorMetrics({}, makeLogger());
  for (let i = 0; i < 99; i++) {
    assert.equal(m.longTermNRMSD(0.1), 0);
  }
  assert.notEqual(m.longTermNRMSD(0.2), 0);
});

test('assessDrift returns expected result envelope', () => {
  const m = new ErrorMetrics({}, makeLogger());
  const out = m.assessDrift([100, 101, 102], [99, 100, 103], 90, 110);

  assert.equal(typeof out.nrmse, 'number');
  assert.equal(typeof out.longTermNRMSD, 'number');
  assert.ok('immediateLevel' in out);
  assert.ok('longTermLevel' in out);
});

test('assessPoint keeps per-metric state and returns metric id', () => {
  const m = new ErrorMetrics({}, makeLogger());
  m.registerMetric('flow', { windowSize: 5, minSamplesForLongTerm: 3, strictValidation: true });

  m.assessPoint('flow', 100, 99, { processMin: 0, processMax: 200, timestamp: Date.now() - 2000 });
  m.assessPoint('flow', 101, 100, { processMin: 0, processMax: 200, timestamp: Date.now() - 1000 });
  const out = m.assessPoint('flow', 102, 101, { processMin: 0, processMax: 200, timestamp: Date.now() });

  assert.equal(out.metricId, 'flow');
  assert.equal(out.valid, true);
  assert.equal(typeof out.nrmse, 'number');
  assert.equal(typeof out.sampleCount, 'number');
});
