import { strict as assert } from 'assert';
import {
  RELATION_FORMULAS,
  AFFINITY_INIMITY_MAP,
  POWER_INFLUENCE_MAP,
  AFFINITY_LABELS,
  INIMITY_LABELS,
  POWER_LABELS,
  INFLUENCE_LABELS,
  SPECIAL_CHARACTERISTICS_TABLE,
} from '../data/allyEnemyTables.js';

import { mapRollToValue, getLabel, clamp } from '../allyEnemyGenerator.js';

let passed = 0;
let failed = 0;

function test(name, fn) {
  try {
    fn();
    passed++;
    console.log(`  PASS  ${name}`);
  } catch (e) {
    failed++;
    console.error(`  FAIL  ${name}\n    ${e.message}`);
  }
}

function assertEqual(actual, expected, msg) {
  assert.strictEqual(actual, expected, msg || `expected ${expected}, got ${actual}`);
}

// ──────────────────────────────────────
console.log('\nmapRollToValue');
// ──────────────────────────────────────
test('maps 2→0', () => assertEqual(mapRollToValue(2, AFFINITY_INIMITY_MAP), 0));
test('maps 3→1', () => assertEqual(mapRollToValue(3, AFFINITY_INIMITY_MAP), 1));
test('maps 5→2', () => assertEqual(mapRollToValue(5, AFFINITY_INIMITY_MAP), 2));
test('maps 7→3', () => assertEqual(mapRollToValue(7, AFFINITY_INIMITY_MAP), 3));
test('maps 9→4', () => assertEqual(mapRollToValue(9, AFFINITY_INIMITY_MAP), 4));
test('maps 11→5', () => assertEqual(mapRollToValue(11, AFFINITY_INIMITY_MAP), 5));
test('maps 12→6', () => assertEqual(mapRollToValue(12, AFFINITY_INIMITY_MAP), 6));
test('unknown roll → 0', () => assertEqual(mapRollToValue(13, AFFINITY_INIMITY_MAP), 0));

test('power 2-5→0', () => { assertEqual(mapRollToValue(2, POWER_INFLUENCE_MAP), 0); assertEqual(mapRollToValue(5, POWER_INFLUENCE_MAP), 0); });
test('power 6-7→1', () => { assertEqual(mapRollToValue(6, POWER_INFLUENCE_MAP), 1); assertEqual(mapRollToValue(7, POWER_INFLUENCE_MAP), 1); });
test('power 8→2', () => assertEqual(mapRollToValue(8, POWER_INFLUENCE_MAP), 2));
test('power 9→3', () => assertEqual(mapRollToValue(9, POWER_INFLUENCE_MAP), 3));
test('power 10→4', () => assertEqual(mapRollToValue(10, POWER_INFLUENCE_MAP), 4));
test('power 11→5', () => assertEqual(mapRollToValue(11, POWER_INFLUENCE_MAP), 5));
test('power 12→6', () => assertEqual(mapRollToValue(12, POWER_INFLUENCE_MAP), 6));

// ──────────────────────────────────────
console.log('\ngetLabel');
// ──────────────────────────────────────
test('finds matching affinity label', () => {
  assertEqual(getLabel(3, AFFINITY_LABELS).label, 'Très bienveillant');
});

test('returns first for out-of-range', () => {
  assertEqual(getLabel(99, AFFINITY_LABELS).label, 'Aucune');
});

test('finds inimity label', () => {
  assertEqual(getLabel(4, INIMITY_LABELS).label, 'Haine');
});

test('finds power label', () => {
  assertEqual(getLabel(5, POWER_LABELS).label, 'Très puissant');
});

test('finds influence label', () => {
  assertEqual(getLabel(2, INFLUENCE_LABELS).label, 'Influence modérée');
});

// ──────────────────────────────────────
console.log('\nclamp');
// ──────────────────────────────────────
test('within range', () => assertEqual(clamp(3, 0, 6), 3));
test('below min', () => assertEqual(clamp(-1, 0, 6), 0));
test('above max', () => assertEqual(clamp(7, 0, 6), 6));
test('edge min', () => assertEqual(clamp(0, 0, 6), 0));
test('edge max', () => assertEqual(clamp(6, 0, 6), 6));

// ──────────────────────────────────────
console.log('\nRELATION_FORMULAS');
// ──────────────────────────────────────
test('ally: 2d6 affinity, 0 inimity', () => {
  assertEqual(RELATION_FORMULAS.ally.affinity, '2d6');
  assertEqual(RELATION_FORMULAS.ally.inimity, '0');
});

test('contact: 1d6+1 affinity, 1d6-1 inimity', () => {
  assertEqual(RELATION_FORMULAS.contact.affinity, '1d6+1');
  assertEqual(RELATION_FORMULAS.contact.inimity, '1d6-1');
});

test('rival: 1d6-1 affinity, 1d6+1 inimity', () => {
  assertEqual(RELATION_FORMULAS.rival.affinity, '1d6-1');
  assertEqual(RELATION_FORMULAS.rival.inimity, '1d6+1');
});

test('enemy: 0 affinity, 2d6 inimity', () => {
  assertEqual(RELATION_FORMULAS.enemy.affinity, '0');
  assertEqual(RELATION_FORMULAS.enemy.inimity, '2d6');
});

// ──────────────────────────────────────
console.log('\nLABELS — array lengths');
// ──────────────────────────────────────
test('AFFINITY_LABELS has 7 entries', () => assertEqual(AFFINITY_LABELS.length, 7));
test('INIMITY_LABELS has 7 entries', () => assertEqual(INIMITY_LABELS.length, 7));
test('POWER_LABELS has 7 entries', () => assertEqual(POWER_LABELS.length, 7));
test('INFLUENCE_LABELS has 7 entries', () => assertEqual(INFLUENCE_LABELS.length, 7));

// ──────────────────────────────────────
console.log('\nSPECIAL_CHARACTERISTICS_TABLE');
// ──────────────────────────────────────
test('has 36 D66 entries', () => assertEqual(SPECIAL_CHARACTERISTICS_TABLE.length, 36));

test('all entries have valid D66 range', () => {
  for (const e of SPECIAL_CHARACTERISTICS_TABLE) {
    if (e.d66 < 11 || e.d66 > 66) throw new Error(`entry d66=${e.d66} out of range`);
    if (!e.text) throw new Error(`entry d66=${e.d66} missing text`);
    if (!e.effects) throw new Error(`entry d66=${e.d66} missing effects`);
  }
});

test('D66 65 is extraRolls 2', () => {
  const e = SPECIAL_CHARACTERISTICS_TABLE.find(x => x.d66 === 65);
  assertEqual(e.effects.action, 'extraRolls');
  assertEqual(e.effects.actionValue, 2);
});

test('D66 66 is extraRolls 3', () => {
  const e = SPECIAL_CHARACTERISTICS_TABLE.find(x => x.d66 === 66);
  assertEqual(e.effects.action, 'extraRolls');
  assertEqual(e.effects.actionValue, 3);
});

test('D66 11 has affinityMod 1', () => {
  const e = SPECIAL_CHARACTERISTICS_TABLE.find(x => x.d66 === 11);
  assertEqual(e.effects.affinityMod, 1);
});

test('D66 44 has setPowerToZero + inimityMod 1', () => {
  const e = SPECIAL_CHARACTERISTICS_TABLE.find(x => x.d66 === 44);
  assertEqual(e.effects.action, 'setPowerToZero');
  assertEqual(e.effects.inimityMod, 1);
});

// ──────────────────────────────────────
console.log('\n');
// ──────────────────────────────────────

if (failed > 0) {
  console.error(`\n  ${failed} of ${passed + failed} tests FAILED\n`);
  process.exit(1);
} else {
  console.log(`  All ${passed} tests passed\n`);
}
