import test from 'node:test';
import assert from 'node:assert/strict';
import {
  parseList,
  hostAllowed,
  ipMatches,
  ipAllowed,
  buildNetworkGuard,
} from './admin-guard.mjs';

test('parseList splits, trims, and drops empties', () => {
  assert.deepEqual(parseList('a, b ,,c'), ['a', 'b', 'c']);
  assert.deepEqual(parseList(''), []);
  assert.deepEqual(parseList(undefined), []);
});

test('hostAllowed: empty list allows all, otherwise matches hostname ignoring port/case', () => {
  assert.equal(hostAllowed('gadm.tkmind.cn:8082', []), true);
  assert.equal(hostAllowed('GADM.tkmind.cn', ['gadm.tkmind.cn']), true);
  assert.equal(hostAllowed('evil.example.com', ['gadm.tkmind.cn']), false);
  assert.equal(hostAllowed('gadm.tkmind.cn:443', ['gadm.tkmind.cn', 'localhost']), true);
});

test('ipMatches: exact and IPv4-mapped IPv6', () => {
  assert.equal(ipMatches('127.0.0.1', '127.0.0.1'), true);
  assert.equal(ipMatches('::ffff:127.0.0.1', '127.0.0.1'), true);
  assert.equal(ipMatches('10.0.0.5', '10.0.0.6'), false);
});

test('ipMatches: CIDR ranges', () => {
  assert.equal(ipMatches('10.1.2.3', '10.0.0.0/8'), true);
  assert.equal(ipMatches('11.1.2.3', '10.0.0.0/8'), false);
  assert.equal(ipMatches('192.168.1.50', '192.168.1.0/24'), true);
  assert.equal(ipMatches('192.168.2.50', '192.168.1.0/24'), false);
  assert.equal(ipMatches('203.0.113.9', '0.0.0.0/0'), true);
  assert.equal(ipMatches('not-an-ip', '10.0.0.0/8'), false);
});

test('ipAllowed: empty list allows all', () => {
  assert.equal(ipAllowed('1.2.3.4', []), true);
  assert.equal(ipAllowed('1.2.3.4', ['10.0.0.0/8']), false);
  assert.equal(ipAllowed('10.9.9.9', ['10.0.0.0/8', '127.0.0.1']), true);
});

test('buildNetworkGuard returns null when nothing configured', () => {
  assert.equal(buildNetworkGuard({ onDeny: () => {} }), null);
});

test('buildNetworkGuard denies on host then ip, allows when both pass', () => {
  const guard = buildNetworkGuard({
    allowedHosts: ['gadm.tkmind.cn'],
    ipAllowlist: ['10.0.0.0/8'],
    onDeny: (_res, _req, reason) => `deny:${reason}`,
  });
  const mk = (host, ip) => ({ get: () => host, ip });

  let nexted = false;
  const next = () => {
    nexted = true;
  };

  assert.equal(guard(mk('evil.com', '10.1.1.1'), {}, next), 'deny:host');
  assert.equal(guard(mk('gadm.tkmind.cn', '8.8.8.8'), {}, next), 'deny:ip');
  assert.equal(nexted, false);
  guard(mk('gadm.tkmind.cn', '10.1.1.1'), {}, next);
  assert.equal(nexted, true);
});
