import { describe, it, expect, beforeEach } from 'vitest';
import { useDisciplineStore } from '../stores/discipline-slice';

function resetDisciplineStore() {
  useDisciplineStore.setState({
    disciplines: {},
    activeIds: [],
    concurrentLimit: 1,
    totalXP: 0,
  });
}

describe('DisciplineStore', () => {
  beforeEach(resetDisciplineStore);

  describe('activate', () => {
    it('should activate raw discipline', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
      expect(useDisciplineStore.getState().disciplines['raw-mastery'].paused).toBe(false);
    });

    it('should not activate same discipline twice', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      useDisciplineStore.getState().activate('raw-mastery');
      expect(useDisciplineStore.getState().activeIds.filter(id => id === 'raw-mastery').length).toBe(1);
    });

    it('should not activate when concurrent limit reached', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      useDisciplineStore.getState().activate('attune-fire');
      expect(useDisciplineStore.getState().activeIds.length).toBe(1);
    });

    it('should not activate capacity discipline when mana type is locked', () => {
      // capacity disciplines now require the mana type to be unlocked
      useDisciplineStore.getState().activate('attune-fire', {
        elements: { fire: { unlocked: false, current: 100, max: 100, baseMax: 100 } },
      });
      expect(useDisciplineStore.getState().activeIds).not.toContain('attune-fire');
    });

    it('should activate capacity discipline when mana type element is unlocked', () => {
      useDisciplineStore.getState().activate('attune-fire', {
        elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } },
      });
      expect(useDisciplineStore.getState().activeIds).toContain('attune-fire');
    });

    it('should activate even with insufficient mana (no drain model)', () => {
      useDisciplineStore.setState({
        disciplines: { 'raw-mastery': { id: 'raw-mastery', xp: 1000, paused: false } },
      });
      useDisciplineStore.getState().activate('raw-mastery', { elements: {} });
      expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
    });

    it('should activate when required element is unlocked', () => {
      useDisciplineStore.getState().activate('attune-fire', {
        elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } },
      });
      expect(useDisciplineStore.getState().activeIds).toContain('attune-fire');
    });
  });

  describe('deactivate', () => {
    it('should remove discipline from active list', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      useDisciplineStore.getState().deactivate('raw-mastery');
      expect(useDisciplineStore.getState().activeIds).not.toContain('raw-mastery');
    });
  });

  describe('processTick', () => {
    it('should accrue XP for active discipline', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
      expect(useDisciplineStore.getState().disciplines['raw-mastery'].xp).toBe(1);
      expect(useDisciplineStore.getState().totalXP).toBe(1);
    });

    it('should drain raw mana when practicing with sufficient mana', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      const result = useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
      // raw-mastery: drainBase=1, xp=0, difficultyFactor=100
      // drain = 1 * (1 + (0/100)^0.4) = 1
      expect(result.rawMana).toBe(999);
    });

    it('should auto-pause discipline when raw mana is insufficient', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      useDisciplineStore.getState().processTick({ rawMana: 0, elements: {} });
      expect(useDisciplineStore.getState().disciplines['raw-mastery'].autoPaused).toBe(true);
    });

    it('should not accrue XP when auto-paused due to insufficient mana', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      useDisciplineStore.getState().processTick({ rawMana: 0, elements: {} });
      expect(useDisciplineStore.getState().disciplines['raw-mastery'].xp).toBe(0);
    });

    it('should auto-pause discipline and report name when element mana is insufficient', () => {
      useDisciplineStore.setState({
        disciplines: {},
        activeIds: [],
        concurrentLimit: 1,
        totalXP: 0,
      });
      // attune-fire has drainBase=2, manaType=fire
      useDisciplineStore.getState().activate('attune-fire', {
        elements: { fire: { unlocked: true, current: 1, max: 100, baseMax: 100 } },
      });
      const result = useDisciplineStore.getState().processTick({ rawMana: 1000, elements: { fire: { unlocked: true, current: 1, max: 100, baseMax: 100 } } });
      expect(useDisciplineStore.getState().disciplines['attune-fire'].autoPaused).toBe(true);
      expect(result.autoPausedNames).toContain('Fire Mana Capacity');
    });

    it('should drain element mana when practicing element discipline with sufficient mana', () => {
      useDisciplineStore.setState({
        disciplines: {},
        activeIds: [],
        concurrentLimit: 1,
        totalXP: 0,
      });
      useDisciplineStore.getState().activate('attune-fire', {
        elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } },
      });
      const result = useDisciplineStore.getState().processTick({ rawMana: 1000, elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } } });
      // attune-fire: drainBase=2, xp=0, difficultyFactor=150
      // drain = 2 * (1 + (0/150)^0.4) = 2
      expect(result.elements.fire.current).toBe(98);
    });

    it('should drain mana for conversion disciplines (regression: was zero cost)', () => {
      useDisciplineStore.setState({
        disciplines: {},
        activeIds: [],
        concurrentLimit: 1,
        totalXP: 0,
      });
      // regen-fire is a conversion discipline with sourceManaTypes: ['raw']
      // It has manaType='fire' and drainBase=1.5 — it MUST drain fire mana
      useDisciplineStore.getState().activate('regen-fire', {
        elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } },
      });
      const result = useDisciplineStore.getState().processTick({ rawMana: 1000, elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } } });
      // Conversion disciplines MUST drain from their mana pool (bug fix #379)
      // regen-fire: drainBase=1.5, xp=0, difficultyFactor=120
      // drain = 1.5 * (1 + (0/120)^0.4) = 1.5
      expect(result.elements.fire.current).toBeCloseTo(98.5, 1);
    });

    it('should auto-pause conversion discipline when element mana is insufficient', () => {
      useDisciplineStore.setState({
        disciplines: {},
        activeIds: [],
        concurrentLimit: 1,
        totalXP: 0,
      });
      // regen-fire has drainBase=1.5, needs at least 1.5 fire mana
      useDisciplineStore.getState().activate('regen-fire', {
        elements: { fire: { unlocked: true, current: 1, max: 100, baseMax: 100 } },
      });
      const result = useDisciplineStore.getState().processTick({ rawMana: 1000, elements: { fire: { unlocked: true, current: 1, max: 100, baseMax: 100 } } });
      expect(useDisciplineStore.getState().disciplines['regen-fire'].autoPaused).toBe(true);
      expect(result.autoPausedNames).toContain('Fire Mana Conversion Speed');
    });

    it('should still accrue XP for conversion disciplines when mana is sufficient', () => {
      useDisciplineStore.setState({
        disciplines: {},
        activeIds: [],
        concurrentLimit: 1,
        totalXP: 0,
      });
      useDisciplineStore.getState().activate('regen-fire', {
        elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } },
      });
      useDisciplineStore.getState().processTick({ rawMana: 1000, elements: { fire: { unlocked: true, current: 100, max: 100, baseMax: 100 } } });
      expect(useDisciplineStore.getState().disciplines['regen-fire'].xp).toBe(1);
    });

    it('should re-activate auto-paused discipline when mana is restored', () => {
      useDisciplineStore.getState().activate('raw-mastery');
      // Auto-pause with 0 mana
      useDisciplineStore.getState().processTick({ rawMana: 0, elements: {} });
      expect(useDisciplineStore.getState().disciplines['raw-mastery'].autoPaused).toBe(true);
      // Re-activate (simulates mana being restored)
      useDisciplineStore.getState().activate('raw-mastery');
      expect(useDisciplineStore.getState().disciplines['raw-mastery'].autoPaused).toBe(false);
      expect(useDisciplineStore.getState().activeIds).toContain('raw-mastery');
    });

    it('should scale drain with XP', () => {
      useDisciplineStore.setState({
        disciplines: { 'raw-mastery': { id: 'raw-mastery', xp: 100, paused: false } },
        activeIds: ['raw-mastery'],
        concurrentLimit: 1,
        totalXP: 100,
      });
      const result = useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
      // raw-mastery: drainBase=1, xp=100, difficultyFactor=100
      // drain = 1 * (1 + (100/100)^0.4) = 1 * (1 + 1) = 2
      expect(result.rawMana).toBe(998);
    });

    it('should increase concurrent limit at 500 total XP', () => {
      useDisciplineStore.setState({ totalXP: 499 });
      useDisciplineStore.getState().activate('raw-mastery');
      useDisciplineStore.getState().processTick({ rawMana: 1000, elements: {} });
      expect(useDisciplineStore.getState().totalXP).toBe(500);
      expect(useDisciplineStore.getState().concurrentLimit).toBeGreaterThan(1);
    });
  });
});
