import { describe, it, expect } from 'vitest';
import { checkDisciplinePrerequisites } from '../utils/discipline-math';
import { DisciplinesAttunementType } from '../types/disciplines';
import type { DisciplineDefinition, DisciplineState } from '../types/disciplines';

// ─── Test Fixtures ────────────────────────────────────────────────────────────

const rawMastery: DisciplineDefinition = {
  id: 'raw-mastery',
  name: 'Raw Mana Mastery',
  attunement: DisciplinesAttunementType.BASE,
  manaType: 'raw',
  baseCost: 5,
  description: 'Learn to harness raw mana more efficiently.',
  statBonus: { stat: 'maxManaBonus', baseValue: 10, label: 'Max Mana Bonus' },
  difficultyFactor: 100,
  scalingFactor: 50,
  drainBase: 1,
  perks: [],
};

const attuneFire: DisciplineDefinition = {
  id: 'attune-fire',
  name: 'Fire Attunement',
  attunement: DisciplinesAttunementType.BASE,
  manaType: 'fire',
  baseCost: 10,
  description: 'Begin focusing raw mana into fire.',
  statBonus: { stat: 'elementCap_fire', baseValue: 5, label: 'Fire Mana Capacity' },
  difficultyFactor: 150,
  scalingFactor: 75,
  drainBase: 2,
  perks: [],
};

// ─── checkDisciplinePrerequisites ─────────────────────────────────────────────

describe('checkDisciplinePrerequisites', () => {
  it('should return canProceed true when no requires field', () => {
    const result = checkDisciplinePrerequisites(rawMastery, {}, [rawMastery]);
    expect(result.canProceed).toBe(true);
    expect(result.missingPrereqs).toEqual([]);
  });

  it('should return canProceed true when prerequisite is met (xp > 0)', () => {
    const disciplines: Record<string, DisciplineState> = {
      'raw-mastery': { id: 'raw-mastery', xp: 100, paused: false },
    };
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'prereq-test',
      requires: ['raw-mastery'],
    };
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, [rawMastery]);
    expect(result.canProceed).toBe(true);
    expect(result.missingPrereqs).toEqual([]);
  });

  it('should return canProceed false when prerequisite has xp = 0', () => {
    const disciplines: Record<string, DisciplineState> = {
      'raw-mastery': { id: 'raw-mastery', xp: 0, paused: true },
    };
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'prereq-test',
      requires: ['raw-mastery'],
    };
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, [rawMastery]);
    expect(result.canProceed).toBe(false);
    expect(result.missingPrereqs).toContain('Raw Mana Mastery');
  });

  it('should return canProceed false when prerequisite state is missing', () => {
    const disciplines: Record<string, DisciplineState> = {};
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'prereq-test',
      requires: ['raw-mastery'],
    };
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, [rawMastery]);
    expect(result.canProceed).toBe(false);
    expect(result.missingPrereqs).toContain('Raw Mana Mastery');
  });

  it('should return missing prereq ID when definition not found in allDefinitions', () => {
    const disciplines: Record<string, DisciplineState> = {};
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'prereq-test',
      requires: ['nonexistent-discipline'],
    };
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, [rawMastery]);
    expect(result.canProceed).toBe(false);
    expect(result.missingPrereqs).toContain('nonexistent-discipline');
  });

  it('should handle multiple prerequisites - all met', () => {
    const disciplines: Record<string, DisciplineState> = {
      'raw-mastery': { id: 'raw-mastery', xp: 100, paused: false },
      'attune-fire': { id: 'attune-fire', xp: 50, paused: false },
    };
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'multi-prereq',
      requires: ['raw-mastery', 'attune-fire'],
    };
    const allDefs = [rawMastery, attuneFire];
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, allDefs);
    expect(result.canProceed).toBe(true);
    expect(result.missingPrereqs).toEqual([]);
  });

  it('should handle multiple prerequisites - some missing', () => {
    const disciplines: Record<string, DisciplineState> = {
      'raw-mastery': { id: 'raw-mastery', xp: 100, paused: false },
    };
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'multi-prereq',
      requires: ['raw-mastery', 'attune-fire'],
    };
    const allDefs = [rawMastery, attuneFire];
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, allDefs);
    expect(result.canProceed).toBe(false);
    expect(result.missingPrereqs.length).toBe(1);
    expect(result.missingPrereqs).toContain('Fire Attunement');
  });

  it('should handle empty requires array', () => {
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'empty-prereqs',
      requires: [],
    };
    const result = checkDisciplinePrerequisites(prereqDisc, {}, [rawMastery]);
    expect(result.canProceed).toBe(true);
    expect(result.missingPrereqs).toEqual([]);
  });

  it('should return canProceed true when mana type requirement is unlocked', () => {
    const disciplines: Record<string, DisciplineState> = {};
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'regen-transference',
      requires: ['transference'],
    };
    const elements = { transference: { unlocked: true } };
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, [rawMastery], elements);
    expect(result.canProceed).toBe(true);
    expect(result.missingPrereqs).toEqual([]);
  });

  it('should return canProceed false when mana type requirement is not unlocked', () => {
    const disciplines: Record<string, DisciplineState> = {};
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'regen-transference',
      requires: ['transference'],
    };
    const elements = { transference: { unlocked: false } };
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, [rawMastery], elements);
    expect(result.canProceed).toBe(false);
    expect(result.missingPrereqs).toContain('transference mana');
  });

  it('should return canProceed false when mana type is missing from elements', () => {
    const disciplines: Record<string, DisciplineState> = {};
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'regen-fire',
      requires: ['fire'],
    };
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, [rawMastery], {});
    expect(result.canProceed).toBe(false);
    expect(result.missingPrereqs).toContain('fire mana');
  });

  it('should not require elements param for backwards compatibility', () => {
    const disciplines: Record<string, DisciplineState> = {};
    const prereqDisc: DisciplineDefinition = {
      ...rawMastery,
      id: 'unknown-req',
      requires: ['unknown-thing'],
    };
    const result = checkDisciplinePrerequisites(prereqDisc, disciplines, [rawMastery]);
    expect(result.canProceed).toBe(false);
    expect(result.missingPrereqs).toContain('unknown-thing');
  });
});
