import { computeApplicableSteps } from './compute-applicable-steps';

describe('computeApplicableSteps — Fighter (martial, no FA, no caster)', () => {
  it('at L5 returns [class-features, boost, skill-increase, feat-ancestry, review] (L5 is odd → no class/skill feat)', () => {
    // PF2e CRB: class feats and skill feats are at even levels (2,4,6,...).
    // L5 grants ability-boosts, skill-increase, and ancestry-feat — but no class/skill feats.
    // (Plan's expected list at L5 was PF2e-incorrect; corrected here per project's "regelkonform" goal.)
    const steps = computeApplicableSteps({
      targetLevel: 5,
      className: 'Fighter',
      hasFreeArchetype: false,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).toEqual([
      'class-features',
      'boost',
      'skill-increase',
      'feat-ancestry',
      'review',
    ]);
  });

  it('at L4 (not a boost level) does NOT contain boost', () => {
    const steps = computeApplicableSteps({
      targetLevel: 4,
      className: 'Fighter',
      hasFreeArchetype: false,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).not.toContain('boost');
  });

  it('at L4 (even level) contains feat-class AND feat-skill', () => {
    const steps = computeApplicableSteps({
      targetLevel: 4,
      className: 'Fighter',
      hasFreeArchetype: false,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).toContain('feat-class');
    expect(steps).toContain('feat-skill');
  });

  it('at L3 contains skill-increase AND feat-general but NOT feat-class (odd level)', () => {
    const steps = computeApplicableSteps({
      targetLevel: 3,
      className: 'Fighter',
      hasFreeArchetype: false,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).toContain('skill-increase');
    expect(steps).toContain('feat-general');
    expect(steps).not.toContain('feat-class');
  });

  it('at L2 (even but no skill-increase yet) contains feat-class+feat-skill but NOT skill-increase', () => {
    const steps = computeApplicableSteps({
      targetLevel: 2,
      className: 'Fighter',
      hasFreeArchetype: false,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).toContain('feat-class');
    expect(steps).toContain('feat-skill');
    expect(steps).not.toContain('skill-increase');
  });
});

describe('computeApplicableSteps — Free Archetype', () => {
  it('with FA enabled at L5 includes feat-archetype', () => {
    const steps = computeApplicableSteps({
      targetLevel: 5,
      className: 'Fighter',
      hasFreeArchetype: true,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).toContain('feat-archetype');
  });

  it('without FA never includes feat-archetype', () => {
    const steps = computeApplicableSteps({
      targetLevel: 5,
      className: 'Fighter',
      hasFreeArchetype: false,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).not.toContain('feat-archetype');
  });
});

describe('computeApplicableSteps — Spellcaster', () => {
  it('with isCaster=true includes spellcaster step', () => {
    const steps = computeApplicableSteps({
      targetLevel: 5,
      className: 'Wizard',
      hasFreeArchetype: false,
      isCaster: true,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).toContain('spellcaster');
  });

  it('with isCaster=false never includes spellcaster step', () => {
    const steps = computeApplicableSteps({
      targetLevel: 5,
      className: 'Fighter',
      hasFreeArchetype: false,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).not.toContain('spellcaster');
  });
});

describe('computeApplicableSteps — class-feature-choice (D-19)', () => {
  it('includes class-feature-choice when ClassProgression carries choiceType', () => {
    const steps = computeApplicableSteps({
      targetLevel: 1,
      className: 'Cleric',
      hasFreeArchetype: false,
      isCaster: true,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: true,
    });
    expect(steps).toContain('class-feature-choice');
  });

  it('does NOT include class-feature-choice when no choiceType', () => {
    const steps = computeApplicableSteps({
      targetLevel: 5,
      className: 'Fighter',
      hasFreeArchetype: false,
      isCaster: false,
      isSpontaneousCaster: false,
      classProgressionHasChoiceType: false,
    });
    expect(steps).not.toContain('class-feature-choice');
  });
});

describe('computeApplicableSteps — invariants', () => {
  it('always starts with class-features', () => {
    for (const level of [1, 2, 3, 5, 10, 15, 20]) {
      const steps = computeApplicableSteps({
        targetLevel: level,
        className: 'Fighter',
        hasFreeArchetype: false,
        isCaster: false,
        isSpontaneousCaster: false,
        classProgressionHasChoiceType: false,
      });
      expect(steps[0]).toBe('class-features');
    }
  });

  it('always ends with review', () => {
    for (const level of [1, 2, 3, 5, 10, 15, 20]) {
      const steps = computeApplicableSteps({
        targetLevel: level,
        className: 'Fighter',
        hasFreeArchetype: false,
        isCaster: false,
        isSpontaneousCaster: false,
        classProgressionHasChoiceType: false,
      });
      expect(steps[steps.length - 1]).toBe('review');
    }
  });
});
