// ─── Per-Enemy Damage Application (spec §3.2) ─────────────────────────────────
// Extracted from combat-actions.ts to stay under the 400-line file limit.

import { ENCHANTMENT_EFFECTS } from '../data/enchantment-effects';
import { ENCHANTMENT_SPELLS } from '../constants/spells';
import { canAffordSpellCost, deductSpellCost } from '../utils';
import type { CombatStore, CombatState } from './combat-state.types';
import type { EnemyState, EquipmentInstance } from '../types';

/**
 * Deduct mana costs for weapon enchant spells on a sword (fireBlade, frostBlade, etc.).
 * Called once per melee hit in the combat tick.
 * Returns updated { rawMana, elements } reflecting any enchant costs.
 */
export function deductWeaponEnchantCosts(
  swordInstance: EquipmentInstance,
  rawMana: number,
  elements: Record<string, { current: number; max: number; unlocked: boolean }>,
): { rawMana: number; elements: Record<string, { current: number; max: number; unlocked: boolean }> } {
  let rm = rawMana;
  let el = elements;
  for (const ench of swordInstance.enchantments) {
    const enchantEffect = ENCHANTMENT_EFFECTS[ench.effectId];
    if (enchantEffect?.effect.type === 'special' && enchantEffect.effect.specialId) {
      const spellDef = ENCHANTMENT_SPELLS[enchantEffect.effect.specialId];
      if (spellDef?.cost) {
        const afterCost = deductSpellCost(spellDef.cost, rm, el);
        rm = afterCost.rawMana;
        el = afterCost.elements;
      }
    }
  }
  return { rawMana: rm, elements: el };
}

/**
 * Find the enemy with the lowest current HP in the room (focus-fire targeting).
 * Returns null if no living enemies exist.
 */
export function lowestHPEnemy(enemies: EnemyState[]): EnemyState | null {
  let lowest: EnemyState | null = null;
  for (const enemy of enemies) {
    if (enemy.hp <= 0) continue;
    if (!lowest || enemy.hp < lowest.hp) {
      lowest = enemy;
    }
  }
  return lowest;
}

/**
 * Apply damage to enemies in the current room.
 *
 * Spec §3.2:
 * - AoE spells: damage is distributed across up to aoeTargets enemies
 * - Single-target: target the enemy with lowest HP (focus-fire)
 * - Recalculates floorHP as sum of all enemy HP
 * - Triggers onRoomCleared when all enemies reach 0 HP
 *
 * @param aoeTargets — max number of enemies hit by AoE (spec §3.2, D-38 fix)
 * @returns { floorHP, floorMaxHP, roomCleared }
 */
export function applyDamageToRoom(
  get: () => CombatStore,
  set: (state: Partial<CombatState>) => void,
  dmg: number,
  isAoe: boolean,
  aoeTargets?: number,
): { floorHP: number; floorMaxHP: number; roomCleared: boolean } {
  const state = get();
  const room = state.currentRoom;
  if (!room || room.enemies.length === 0) {
    // No enemies in room — fall back to direct floorHP subtraction
    const newFloorHP = Math.max(0, state.floorHP - dmg);
    set({ floorHP: newFloorHP });
    return { floorHP: newFloorHP, floorMaxHP: state.floorMaxHP, roomCleared: newFloorHP <= 0 };
  }

  // For single-target, find the lowest HP enemy once (focus-fire)
  const singleTarget = isAoe ? null : lowestHPEnemy(room.enemies);

  // For AoE, select up to aoeTargets living enemies (focus-fire: lowest HP first)
  let aoeTargetSet: Set<string> | null = null;
  if (isAoe && aoeTargets && aoeTargets > 0) {
    const livingEnemies = room.enemies
      .filter(e => e.hp > 0)
      .sort((a, b) => a.hp - b.hp);
    const targets = livingEnemies.slice(0, aoeTargets);
    aoeTargetSet = new Set(targets.map(e => e.id));
  }

  const updatedEnemies = room.enemies.map((enemy) => {
    if (enemy.hp <= 0) return enemy;
    if (isAoe) {
      // AoE: distribute damage across up to aoeTargets enemies (spec §3.2, D-38 fix)
      if (aoeTargetSet && !aoeTargetSet.has(enemy.id)) return enemy;
      const dmgPerEnemy = aoeTargetSet ? dmg / aoeTargetSet.size : dmg;
      return { ...enemy, hp: Math.max(0, enemy.hp - dmgPerEnemy) };
    }
    // Single-target: only damage the lowest HP enemy
    if (singleTarget && enemy.id === singleTarget.id) {
      return { ...enemy, hp: Math.max(0, enemy.hp - dmg) };
    }
    return enemy;
  });

  const newFloorHP = updatedEnemies.reduce((sum, e) => sum + e.hp, 0);
  const allDead = updatedEnemies.every((e) => e.hp <= 0);

  set({
    currentRoom: { ...room, enemies: updatedEnemies },
    floorHP: newFloorHP,
  });

  return { floorHP: newFloorHP, floorMaxHP: state.floorMaxHP, roomCleared: allDead };
}
