import { describe, it, expect, beforeEach } from 'vitest';
import { ProgressionManager } from '../ProgressionManager';
import { type CombatantActor } from '../../core/types';

describe('ProgressionManager', () => {
  let progressionManager: ProgressionManager;
  let mockPlayer: CombatantActor;

  beforeEach(() => {
    progressionManager = new ProgressionManager();
    mockPlayer = {
      id: 1,
      category: 'combatant',
      isPlayer: true,
      pos: { x: 0, y: 0 },
      speed: 100,
      stats: {
        maxHp: 20,
        hp: 20,
      maxMana: 0,
      mana: 0,
        level: 1,
        exp: 0,
        expToNextLevel: 100,
        statPoints: 5,
        skillPoints: 2,
        strength: 10,
        dexterity: 10,
        intelligence: 10,
        attack: 5,
        defense: 2,
        critChance: 5,
        critMultiplier: 150,
        accuracy: 90,
        lifesteal: 0,
        evasion: 5,
        blockChance: 0,
        luck: 0,
        passiveNodes: []
      }
    } as any;
  });

  it('should allocate strength and increase maxHp and attack', () => {
    progressionManager.allocateStat(mockPlayer, 'strength');
    expect(mockPlayer.stats.strength).toBe(11);
    expect(mockPlayer.stats.maxHp).toBe(22);
    expect(mockPlayer.stats.hp).toBe(22);
    expect(mockPlayer.stats.attack).toBeCloseTo(5.2);
    expect(mockPlayer.stats.statPoints).toBe(4);
  });

  it('should allocate dexterity and increase speed', () => {
    progressionManager.allocateStat(mockPlayer, 'dexterity');
    expect(mockPlayer.stats.dexterity).toBe(11);
    expect(mockPlayer.speed).toBe(101);
    expect(mockPlayer.stats.statPoints).toBe(4);
  });

  it('should allocate intelligence and increase defense every 5 points', () => {
    // Current INT is 10 (multiple of 5)
    // Next multiple is 15
    progressionManager.allocateStat(mockPlayer, 'intelligence');
    expect(mockPlayer.stats.intelligence).toBe(11);
    expect(mockPlayer.stats.defense).toBe(2); // No increase yet

    mockPlayer.stats.intelligence = 14;
    mockPlayer.stats.statPoints = 1;
    progressionManager.allocateStat(mockPlayer, 'intelligence');
    expect(mockPlayer.stats.intelligence).toBe(15);
    expect(mockPlayer.stats.defense).toBe(3); // Increased!
  });

  it('should not allocate stats if statPoints are 0', () => {
    mockPlayer.stats.statPoints = 0;
    progressionManager.allocateStat(mockPlayer, 'strength');
    expect(mockPlayer.stats.strength).toBe(10);
  });

  it('should apply passive node bonuses', () => {
    progressionManager.allocatePassive(mockPlayer, 'off_1');
    expect(mockPlayer.stats.attack).toBe(7);
    expect(mockPlayer.stats.skillPoints).toBe(1);
    expect(mockPlayer.stats.passiveNodes).toContain('off_1');

    progressionManager.allocatePassive(mockPlayer, 'util_2');
    expect(mockPlayer.stats.expToNextLevel).toBe(90);
    expect(mockPlayer.stats.skillPoints).toBe(0);
  });

  it('should not apply the same passive twice', () => {
    progressionManager.allocatePassive(mockPlayer, 'off_1');
    const pointsAfterFirst = mockPlayer.stats.skillPoints;
    progressionManager.allocatePassive(mockPlayer, 'off_1');
    expect(mockPlayer.stats.skillPoints).toBe(pointsAfterFirst);
    expect(mockPlayer.stats.attack).toBe(7); // Same as before
  });
});
