import { recomputeDerivedStats } from './recompute-derived-stats';
import type { CharacterContext, ClassProgressionRow, WizardChoices, Proficiency } from './types';

type RecomputeInput = CharacterContext & {
  ancestryHp: number;
  classHp: number;
  armorAc: number;
  armorProficiency: Proficiency;
  dexCap: number;
};

function baseCharacter(overrides: Partial<RecomputeInput> = {}): RecomputeInput {
  return {
    level: 4,
    className: 'Fighter',
    ancestryName: 'Human',
    heritageName: undefined,
    abilities: { STR: 18, DEX: 14, CON: 16, INT: 10, WIS: 12, CHA: 10 },
    skills: {},
    feats: new Set(),
    ancestryHp: 8,
    classHp: 10,
    armorAc: 4,
    armorProficiency: 'EXPERT',
    dexCap: 2,
    ...overrides,
  };
}

function emptyProgression(level: number): ClassProgressionRow {
  return {
    className: 'Fighter',
    level,
    grants: [],
    proficiencyChanges: {},
  };
}

describe('recomputeDerivedStats — hpMax', () => {
  it('computes hpMax = ancestryHP + (classHP + conMod) × newLevel for L4 → L5 Fighter, CON 16', () => {
    // CON 16 → mod +3; classHP 10 + 3 = 13 per level; ancestryHP 8; L5: 8 + 13×5 = 73
    const ch = baseCharacter();
    const choices: WizardChoices = {};
    const result = recomputeDerivedStats(ch, choices, emptyProgression(5));
    expect(result.hpMax).toBe(73);
  });

  it('respects boost-cap-at-18 when CON is boosted from 18', () => {
    // CON starts at 18, boost target includes CON → new CON = 19 (not 20). conMod = +4.
    // L5: 8 + (10+4)×5 = 78
    const ch = baseCharacter({
      abilities: { STR: 16, DEX: 14, CON: 18, INT: 10, WIS: 12, CHA: 10 },
    });
    const choices: WizardChoices = { boostTargets: ['CON', 'STR', 'DEX', 'INT'] };
    const result = recomputeDerivedStats(ch, choices, emptyProgression(5));
    expect(result.hpMax).toBe(78);
  });
});

describe('recomputeDerivedStats — proficiencyChanges from ClassProgression', () => {
  it('applies proficiencyChanges from ClassProgression at the new level (fortitude EXPERT)', () => {
    // Fighter L4 → L5 with progression bumping fort to EXPERT.
    // CON mod +3, level 5; fort = conMod + (level + 4) = 3 + 9 = 12
    const ch = baseCharacter();
    const progression: ClassProgressionRow = {
      ...emptyProgression(5),
      proficiencyChanges: { fortitude: 'EXPERT' },
    };
    const result = recomputeDerivedStats(ch, {}, progression);
    expect(result.fortitude).toBe(12);
  });
});

describe('recomputeDerivedStats — Pitfall #9 (hpCurrent must not be in output)', () => {
  it('does NOT include hpCurrent in the result object', () => {
    const ch = baseCharacter();
    const result = recomputeDerivedStats(ch, {}, emptyProgression(5));
    expect(result).not.toHaveProperty('hpCurrent');
    expect(result).not.toHaveProperty('hpTemp');
  });
});

describe('recomputeDerivedStats — level passthrough', () => {
  it('returns the new level in the output', () => {
    const ch = baseCharacter();
    const result = recomputeDerivedStats(ch, {}, emptyProgression(5));
    expect(result.level).toBe(5);
  });
});
