import { describe, it, expect } from 'vitest';
import { generateFloorState } from '../utils/room-utils';
import { SWARM_CONFIG } from '../constants';
import { getGuardianForFloor } from '../data/guardian-encounters';
import { getFloorMaxHP } from '../utils/floor-utils';
import { getDodgeChance } from '../utils/room-utils';

// ─── generateFloorState ───────────────────────────────────────────────────────

describe('generateFloorState', () => {
  it('should return a FloorState object', () => {
    const state = generateFloorState(1);
    expect(typeof state).toBe('object');
    expect(state).toHaveProperty('roomType');
    expect(state).toHaveProperty('enemies');
  });

  it('should generate guardian state for guardian floor', () => {
    const state = generateFloorState(10);
    expect(state.roomType).toBe('guardian');
    expect(state.enemies.length).toBe(1);
    const g10 = getGuardianForFloor(10)!;
    expect(state.enemies[0].name).toBe(g10.name);
    expect(state.enemies[0].hp).toBe(g10.hp);
    expect(state.enemies[0].element).toBe(g10.element.join('+'));
  });

  it('should generate combat state for non-guardian floor with combat', () => {
    const originalRandom = Math.random;
    Math.random = () => 0.5; // Won't trigger special rooms
    const state = generateFloorState(5);
    expect(state.roomType).toBe('combat');
    expect(state.enemies.length).toBe(1);
    expect(state.enemies[0].hp).toBe(getFloorMaxHP(5));
    Math.random = originalRandom;
  });

  it('should generate swarm state for swarm room', () => {
    const originalRandom = Math.random;
    Math.random = () => 0.14; // < SWARM_ROOM_CHANCE (0.15)
    const state = generateFloorState(5);
    expect(state.roomType).toBe('swarm');
    expect(Array.isArray(state.enemies)).toBe(true);
    expect(state.enemies.length).toBeGreaterThanOrEqual(SWARM_CONFIG.minEnemies);
    Math.random = originalRandom;
  });

  it('should generate speed state for speed room', () => {
    // Note: In the current implementation, swarm is checked before speed.
    // Speed rooms can only be generated if random >= SWARM_ROOM_CHANCE (0.15)
    // AND random < SPEED_ROOM_CHANCE (0.10), which is impossible since 0.15 > 0.10.
    // This test verifies the speed code path exists by using a mock that
    // bypasses the swarm check.
    const originalRandom = Math.random;
    // First call (swarm check) returns >= 0.15, second call (speed check) returns < 0.10
    let callCount = 0;
    Math.random = () => {
      callCount++;
      if (callCount === 1) return 0.16; // >= SWARM_ROOM_CHANCE, skip swarm
      if (callCount === 2) return 0.05; // < SPEED_ROOM_CHANCE, trigger speed
      return 0.5;
    };
    const state = generateFloorState(5);
    expect(state.roomType).toBe('speed');
    expect(state.enemies.length).toBe(1);
    Math.random = originalRandom;
  });

  it('should generate puzzle state for puzzle room', () => {
    const originalRandom = Math.random;
    Math.random = () => 0.19; // < PUZZLE_ROOM_CHANCE (0.20)
    const state = generateFloorState(7);
    expect(state.roomType).toBe('puzzle');
    expect(Array.isArray(state.enemies)).toBe(true);
    expect(state.enemies).toEqual([]);
    expect(state.puzzleProgress).toBe(0);
    expect(typeof state.puzzleRequired).toBe('number');
    expect(typeof state.puzzleId).toBe('string');
    expect(typeof state.puzzleAttunements).toBe('object');
    Math.random = originalRandom;
  });

  it('should fill puzzle attunements from PUZZLE_ROOMS', () => {
    const originalRandom = Math.random;
    Math.random = () => 0.19;
    const state = generateFloorState(7);
    expect(state.roomType).toBe('puzzle');
    expect(state.puzzleAttunements!.length).toBeGreaterThan(0);
    expect(typeof state.puzzleAttunements![0]).toBe('string');
    Math.random = originalRandom;
  });

  it('should use correct element for floor', () => {
    const state = generateFloorState(1);
    expect(state.enemies[0].element).toBe('fire');
    const state2 = generateFloorState(2);
    expect(state2.enemies[0].element).toBe('water');
  });

  it('combat enemy HP should match floor max HP', () => {
    const state = generateFloorState(50);
    expect(state.enemies[0].hp).toBe(getFloorMaxHP(50));
  });

  it('speed room should have correct dodge chance', () => {
    // Use a mock that bypasses swarm check and triggers speed
    const originalRandom = Math.random;
    let callCount = 0;
    Math.random = () => {
      callCount++;
      if (callCount === 1) return 0.16; // >= SWARM_ROOM_CHANCE, skip swarm
      if (callCount === 2) return 0.05; // < SPEED_ROOM_CHANCE, trigger speed
      return 0.5;
    };
    const speedState = generateFloorState(51);
    expect(speedState.roomType).toBe('speed');
    expect(speedState.enemies[0].dodgeChance).toBe(getDodgeChance(51));
    Math.random = originalRandom;
  });

  it('should handle very high floor number', () => {
    const state = generateFloorState(1000);
    expect(state.roomType).toBe('guardian');
  });

  it('should handle floor 0', () => {
    // Floor 0: getGuardianForFloor(0) returns null, 0 % 7 === 0
    // With real random, it could be puzzle. Mock to ensure combat.
    const originalRandom = Math.random;
    Math.random = () => 0.5; // High random, won't trigger puzzle
    const state = generateFloorState(0);
    expect(state.roomType).toBe('combat');
    Math.random = originalRandom;
  });
});
