// ─── Spire Utility Functions ───────────────────────────────────────────────────
// Spire-specific utility functions for room generation, enemy stat scaling, etc.

import type { RoomType, FloorState, EnemyState } from '../types';
import type { LootDrop } from '../types/game';
import { PUZZLE_ROOMS } from '../constants';
import { getAvailableDrops, rollLootDrops } from '../data/loot-drops';
import { getFloorMaxHP, getFloorElement } from './floor-utils';
import { getEnemyName } from './enemy-utils';
import { getGuardianForFloor, isGuardianFloor } from '../data/guardian-encounters';

// ─── Spire Room Configuration ─────────────────────────────────────────────────

export const SPIRE_CONFIG = {
  minRoomsPerFloor: 5,
  maxRoomsPerFloor: 15,
  guardianRooms: 1,
  puzzleRoomChance: 0.12,
  rareRoomChance: 0.05,
  recoveryRoomChance: 0.4,
  libraryRoomChance: 0.3,
  treasureRoomChance: 0.3,
};

// ─── Seeded PRNG ──────────────────────────────────────────────────────────────
// Simple mulberry32-style seeded RNG for deterministic room counts & types.

function makeSeededRandom(seed: number): () => number {
  let s = seed | 0;
  return () => {
    s = (s + 0x6d2b79f5) | 0;
    let t = Math.imul(s ^ (s >>> 15), 1 | s);
    t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t;
    return ((t ^ (t >>> 14)) >>> 0) / 4294967296;
  };
}

// ─── Room Count (spec §4.2) ───────────────────────────────────────────────────
// Deterministic per floor via seed = floor × 12345 + runId.
// Guardian floors always return 1.

export function getRoomsForFloor(floor: number, seed: number): number {
  if (isGuardianFloor(floor)) return 1;
  const base = 5;
  const floorBonus = Math.min(10, Math.floor(floor / 20));

  // Use seeded random; seed should be floor × 12345 + runId per spec
  const randomVariation = Math.floor(makeSeededRandom(seed)() * 3);

  return base + floorBonus + randomVariation;
}

// ─── Spire Room Types ─────────────────────────────────────────────────────────

export type SpireRoomType = RoomType | 'recovery' | 'library' | 'treasure';

// ─── Room Type Generation (spec §4.3) ─────────────────────────────────────────

export function generateSpireRoomType(
  floor: number,
  roomIndex: number,
  totalRooms: number,
  runId: number = 0,
): SpireRoomType {
  // Last room on guardian floors is always guardian
  if (isGuardianFloor(floor) && roomIndex === totalRooms - 1) {
    return 'guardian';
  }

  // Override: every 7th floor, one room (chosen by seed) is always 'puzzle'
  if (floor % 7 === 0) {
    const puzzleIndex = Math.floor(makeSeededRandom(floor * 12345 + runId + 7)() * totalRooms);
    if (roomIndex === puzzleIndex) {
      return 'puzzle';
    }
  }

  // Base roll — seed includes runId for per-run variety
  const roll = makeSeededRandom(floor * 1000 + roomIndex + runId)();

  if (roll < 0.10) {
    // Rare roll — secondary roll determines sub-type
    const rareRoll = makeSeededRandom(floor * 1000 + roomIndex + runId + 9999)();
    if (rareRoll < 0.40) return 'recovery';
    if (rareRoll < 0.70) return 'treasure';
    return 'library';
  }
  if (roll < 0.22) return 'swarm';
  if (roll < 0.32) return 'speed';
  return 'combat';
}

// ─── Floor State Generation ───────────────────────────────────────────────────

export function generateSpireFloorState(floor: number, roomIndex: number, totalRooms: number, runId: number = 0): FloorState {
  const roomType = generateSpireRoomType(floor, roomIndex, totalRooms, runId);
  const element = getFloorElement(floor);
  const baseHP = getFloorMaxHP(floor);

  switch (roomType) {
    case 'guardian': {
      const guardian = getGuardianForFloor(floor);
      if (guardian) {
        return {
          roomType: 'guardian',
          enemies: [{
            id: 'guardian',
            name: guardian.name,
            hp: guardian.hp,
            maxHP: guardian.hp,
            armor: guardian.armor || 0,
            dodgeChance: 0,
            barrier: 0,
            element: guardian.element.join('+'),
            activeEffects: [],
            effectiveArmor: guardian.armor || 0,
          }],
        };
      }
      // Fallback if no guardian defined for this floor
      return generateCombatRoom(floor, element, baseHP);
    }

    case 'swarm':
      return generateSwarmRoom(floor, element, baseHP);

    case 'speed':
      return generateSpeedRoom(floor, element, baseHP);

    case 'puzzle': {
      const puzzleKeys = Object.keys(PUZZLE_ROOMS);
      const puzzleIdx = Math.floor(
        makeSeededRandom(floor * 1000 + roomIndex + runId + 5000)() * puzzleKeys.length,
      );
      const selectedPuzzle = puzzleKeys[puzzleIdx];
      const puzzle = PUZZLE_ROOMS[selectedPuzzle];
      return {
        roomType: 'puzzle',
        enemies: [],
        puzzleProgress: 0,
        puzzleRequired: 1,
        puzzleId: selectedPuzzle,
        puzzleAttunements: puzzle.attunements,
      };
    }

    case 'recovery':
      return {
        roomType: 'recovery',
        enemies: [],
        recoveryProgress: 0,
        recoveryRequired: 1,
      };

    case 'library':
      return {
        roomType: 'library',
        enemies: [],
        libraryProgress: 0,
        libraryRequired: 1,
      };

    case 'treasure': {
      const loot = generateTreasureLoot(floor, runId);
      return {
        roomType: 'treasure',
        enemies: [],
        treasureProgress: 0,
        treasureRequired: 1,
        treasureLoot: loot,
        treasureLootClaimed: [],
      };
    }

    default:
      return generateCombatRoom(floor, element, baseHP);
  }
}

function generateCombatRoom(floor: number, element: string, baseHP: number): FloorState {
  const armor = getSpireEnemyArmor(floor);
  const barrier = getSpireEnemyBarrier(floor, element);
  const enemyName = getEnemyName(element, floor);

  return {
    roomType: 'combat',
    enemies: [{
      id: 'enemy',
      name: enemyName,
      hp: baseHP,
      maxHP: baseHP,
      armor,
      dodgeChance: 0,
      barrier,
      element,
      activeEffects: [],
      effectiveArmor: armor,
    }],
  };
}

function generateSwarmRoom(floor: number, element: string, baseHP: number): FloorState {
  const rng = makeSeededRandom(floor * 7777);
  const numEnemies = 3 + Math.floor(rng() * 5); // 3-7 enemies
  const enemies: EnemyState[] = [];

  for (let i = 0; i < numEnemies; i++) {
    enemies.push({
      id: `swarm_${i}`,
      name: `${getEnemyName(element, floor)} ${i + 1}`,
      hp: Math.floor(baseHP * 0.35),
      maxHP: Math.floor(baseHP * 0.35),
      armor: Math.floor(floor / 15) * 0.02,
      dodgeChance: 0,
      barrier: 0,
      element,
      activeEffects: [],
      effectiveArmor: Math.floor(floor / 15) * 0.02,
    });
  }

  return { roomType: 'swarm', enemies };
}

function generateSpeedRoom(floor: number, element: string, baseHP: number): FloorState {
  const dodgeChance = Math.min(0.55, 0.20 + floor * 0.005);
  const armor = getSpireEnemyArmor(floor);

  return {
    roomType: 'speed',
    enemies: [{
      id: 'agile_enemy',
      name: `Agile ${getEnemyName(element, floor)}`,
      hp: baseHP,
      maxHP: baseHP,
      armor,
      dodgeChance,
      barrier: getSpireEnemyBarrier(floor, element),
      element,
      activeEffects: [],
      effectiveArmor: armor,
    }],
  };
}

// ─── Enemy Stat Scaling ───────────────────────────────────────────────────────

export function getSpireEnemyArmor(floor: number, seed: number = floor * 31337): number {
  if (floor < 10) return 0;
  const rng = makeSeededRandom(seed);
  const baseChance = Math.min(0.5, (floor - 10) * 0.01);
  if (rng() > baseChance) return 0;
  const minArmor = 0.05;
  const maxArmor = 0.30;
  const progress = Math.min(1, (floor - 10) / 90);
  return minArmor + (maxArmor - minArmor) * progress * rng();
}

export function getSpireEnemyBarrier(floor: number, element: string, seed: number = floor * 5773): number {
  if (floor < 15) return 0;
  const rng = makeSeededRandom(seed);
  const barrierElements = ['light', 'water', 'earth'];
  const baseChance = barrierElements.includes(element) ? 0.12 : 0.06;
  const floorBonus = Math.min(0.2, (floor - 15) * 0.003);
  if (rng() > Math.min(0.35, baseChance + floorBonus)) return 0;
  const progress = Math.min(1, (floor - 15) / 85);
  return 0.1 + progress * 0.2;
}

// ─── Insight Calculation ──────────────────────────────────────────────────────

export function calcInsight(floor: number, isGuardian: boolean): number {
  const base = Math.floor(Math.pow(floor, 1.2));
  return isGuardian ? Math.floor(base * 2.5) : base;
}

// ─── Room Type Display ────────────────────────────────────────────────────────

/**
 * Generate treasure loot for a treasure room based on floor.
 * Returns pre-generated loot drops that are progressively revealed.
 */
export function generateTreasureLoot(floor: number, runId: number = 0): LootDrop[] {
  const available = getAvailableDrops(floor, false);
  const drops: LootDrop[] = [];

  // Use seeded random for deterministic loot
  const rng = makeSeededRandom(floor * 12345 + runId + 31337);

  // Determine item count based on floor
  let itemCount: number;
  if (floor <= 10) {
    itemCount = 2 + Math.floor(rng() * 2); // 2-3
  } else if (floor <= 50) {
    itemCount = 4 + Math.floor(rng() * 4); // 4-7
  } else {
    itemCount = 8 + Math.floor(rng() * 8); // 8-15
  }

  // Roll for each item
  for (let i = 0; i < itemCount; i++) {
    const rolled = rollLootDrops(floor, false, 0);
    for (const { drop, amount } of rolled) {
      // For materials, add amount; for others, just add the drop
      const existing = drops.find(d => d.id === drop.id);
      if (existing && existing.amount) {
        existing.amount = {
          min: existing.amount.min + (drop.amount?.min ?? 1),
          max: existing.amount.max + (drop.amount?.max ?? amount),
        };
      } else {
        drops.push({ ...drop, amount: drop.amount || { min: amount, max: amount } });
      }
    }
  }

  // Ensure at least one item
  if (drops.length === 0) {
    const fallback = available.find(d => d.type === 'material' && d.rarity === 'common');
    if (fallback) {
      drops.push({ ...fallback, amount: { min: 1, max: 3 } });
    }
  }

  return drops;
}

export function getSpireRoomTypeDisplay(roomType: SpireRoomType): { label: string; icon: string; color: string } {
  const displays: Record<string, { label: string; icon: string; color: string }> = {
    combat: { label: 'Combat', icon: '⚔️', color: '#EF4444' },
    swarm: { label: 'Swarm', icon: '🐝', color: '#F59E0B' },
    speed: { label: 'Speed', icon: '💨', color: '#3B82F6' },
    guardian: { label: 'Guardian', icon: '🛡️', color: '#EF4444' },
    puzzle: { label: 'Puzzle', icon: '🧩', color: '#8B5CF6' },
    recovery: { label: 'Recovery', icon: '💚', color: '#10B981' },
    library: { label: 'Ancient Library', icon: '📚', color: '#6366F1' },
    treasure: { label: 'Treasure', icon: '💎', color: '#F59E0B' },
  };
  return displays[roomType] || { label: 'Unknown', icon: '❓', color: '#6B7280' };
}
