// ─── Golem Combat Helpers ─────────────────────────────────────────────────────
// Shared helpers for golem combat: enchantment resolution, basic attack damage,
// and store-wrapper for processGolemAttacks.
// Extracted from golem-combat-actions.ts to stay under the 400-line file limit.

import { GOLEM_ENCHANTMENTS } from '../data/golems';
import { getElementalBonus } from '../utils';
import type { CombatStore, CombatState } from './combat-state.types';
import type {
  ActiveEffect,
  EnemyState,
  RuntimeActiveGolem,
} from '../types';

// ─── Enchantment Effect Types ────────────────────────────────────────────────

export interface GolemEnchantmentEffect {
  type: 'burn' | 'slow' | 'shock' | 'weaken' | 'armorPierce' | 'criticalChance' | 'soak' | 'shieldBreak';
  magnitude: number;
}

// ─── Enchantment Resolution ──────────────────────────────────────────────────

/** Resolve enchantment effects from a list of enchantment IDs. */
export function resolveEnchantmentEffects(enchantmentIds: string[]): GolemEnchantmentEffect[] {
  const effects: GolemEnchantmentEffect[] = [];
  for (const id of enchantmentIds) {
    const ench = GOLEM_ENCHANTMENTS[id];
    if (!ench) continue;
    switch (ench.effect) {
      case 'burn': effects.push({ type: 'burn', magnitude: 3 }); break;
      case 'slow': effects.push({ type: 'slow', magnitude: 0.3 }); break;
      case 'shock': effects.push({ type: 'shock', magnitude: 0.25 }); break;
      case 'weaken': effects.push({ type: 'weaken', magnitude: 0.2 }); break;
      case 'armorPierce': effects.push({ type: 'armorPierce', magnitude: 0.15 }); break;
      case 'criticalChance': effects.push({ type: 'criticalChance', magnitude: 0.1 }); break;
      case 'soak': effects.push({ type: 'soak', magnitude: 0.3 }); break;
      case 'shieldBreak': effects.push({ type: 'shieldBreak', magnitude: 0.25 }); break;
    }
  }
  return effects;
}

// ─── Basic Attack Damage ─────────────────────────────────────────────────────

/**
 * Compute basic attack damage for a golem.
 * Formula per spire-combat spec §9.4: dmg = frame.baseDamage × (1 + frame.armorPierce)
 * Also applies elemental matchup bonus and enchantment armor pierce bonus.
 * Enemy armor reduction is handled separately in onDamageDealt.
 */
export function computeBasicAttackDamage(
  frame: { baseDamage: number; armorPierce: number; element?: string },
  enchantmentBonusArmorPierce: number,
  _enemyArmor: number,
  enemyElement: string,
): number {
  let dmg = frame.baseDamage;
  if (frame.element) {
    dmg *= getElementalBonus(frame.element, enemyElement);
  }
  const totalArmorPierce = frame.armorPierce + enchantmentBonusArmorPierce;
  dmg *= (1 + totalArmorPierce);
  return Math.max(0, dmg);
}

// ─── Basic Attack Processing ────────────────────────────────────────────────

export interface BasicAttackContext {
  frame: { baseDamage: number; armorPierce: number; element?: string; aoeTargets: number };
  bonusArmorPierce: number;
  enchantmentEffects: GolemEnchantmentEffect[];
  enemyElement: string;
  getTargetEnemy: () => EnemyState | null;
  getTargetEnemies: () => EnemyState[];
  onDamageDealt: (damage: number, skipSpecials?: boolean) => {
    rawMana: number;
    elements: Record<string, { current: number; max: number; unlocked: boolean }>;
    modifiedDamage?: number;
  };
  applyDamageToRoom: (dmg: number) => { floorHP: number; floorMaxHP: number; roomCleared: boolean };
  onApplyEnchantmentEffects: (enemyId: string, effects: GolemEnchantmentEffect[]) => void;
}

export interface BasicAttackResult {
  rawMana: number;
  elements: Record<string, { current: number; max: number; unlocked: boolean }>;
  floorHP: number;
  floorMaxHP: number;
  totalDamageDealt: number;
}

/**
 * Process a single basic attack (AoE or single-target) for a golem.
 * AoE frames distribute damage across up to frame.aoeTargets enemies (spec §11).
 * Single-target frames attack the lowest-HP enemy.
 */
export function processBasicAttack(ctx: BasicAttackContext, currentRawMana: number, currentElements: Record<string, { current: number; max: number; unlocked: boolean }>): BasicAttackResult {
  let rawMana = currentRawMana;
  let elements: Record<string, { current: number; max: number; unlocked: boolean }> = { ...currentElements };
  let floorHP = 0;
  let floorMaxHP = 0;
  let totalDamageDealt = 0;

  if (ctx.frame.aoeTargets > 1) {
    const allEnemies = ctx.getTargetEnemies();
    if (allEnemies.length > 0) {
      const targets = allEnemies.slice(0, ctx.frame.aoeTargets);
      const dmgPerTarget = computeBasicAttackDamage(ctx.frame, ctx.bonusArmorPierce, 0, ctx.enemyElement) / targets.length;
      for (const target of targets) {
        if (ctx.enchantmentEffects.length > 0) {
          ctx.onApplyEnchantmentEffects(target.id, ctx.enchantmentEffects);
        }
        const dmgResult = ctx.onDamageDealt(dmgPerTarget, true);
        const finalDamage = dmgResult.modifiedDamage || dmgPerTarget;
        if (Number.isFinite(finalDamage)) {
          const roomResult = ctx.applyDamageToRoom(finalDamage);
          floorHP = roomResult.floorHP;
          floorMaxHP = roomResult.floorMaxHP;
          totalDamageDealt += Math.max(0, finalDamage);
          rawMana = dmgResult.rawMana;
          elements = dmgResult.elements;
        }
      }
    }
  } else {
    const targetEnemy = ctx.getTargetEnemy();
    const dmg = computeBasicAttackDamage(ctx.frame, ctx.bonusArmorPierce, 0, ctx.enemyElement);
    if (ctx.enchantmentEffects.length > 0 && targetEnemy) {
      ctx.onApplyEnchantmentEffects(targetEnemy.id, ctx.enchantmentEffects);
    }
    const dmgResult = ctx.onDamageDealt(dmg, true);
    const finalDamage = dmgResult.modifiedDamage || dmg;
    if (Number.isFinite(finalDamage)) {
      const roomResult = ctx.applyDamageToRoom(finalDamage);
      floorHP = roomResult.floorHP;
      floorMaxHP = roomResult.floorMaxHP;
      totalDamageDealt += Math.max(0, finalDamage);
      rawMana = dmgResult.rawMana;
      elements = dmgResult.elements;
    }
  }

  return { rawMana, elements, floorHP, floorMaxHP, totalDamageDealt };
}

// ─── Golem Attacks Store Wrapper ─────────────────────────────────────────────

// Import here is safe: only used inside the function body, not at module init time.
import { processGolemAttacks } from './golem-combat-actions'; // eslint-disable-line
import type { GolemCombatResult } from './golem-combat-actions';

interface SerializedDesign {
  id: string;
  name: string;
  coreId: string;
  frameId: string;
  mindCircuitId: string;
  enchantmentIds: string[];
  selectedManaTypes: string[];
  selectedSpells: string[];
}

/** Convenience wrapper that wires up processGolemAttacks with store callbacks. */
export function processGolemAttacksFromStore(
  activeGolems: RuntimeActiveGolem[],
  golemDesigns: Record<string, SerializedDesign>,
  onDamageDealt: (damage: number) => {
    rawMana: number;
    elements: Record<string, { current: number; max: number; unlocked: boolean }>;
    modifiedDamage?: number;
  },
  golemApplyDamageToRoom: (dmg: number) => { floorHP: number; floorMaxHP: number; roomCleared: boolean },
  enemyElement: string,
  get: () => CombatStore,
  set: (s: Partial<CombatState>) => void,
  currentRawMana: number,
  currentElements: Record<string, { current: number; max: number; unlocked: boolean }>,
): GolemCombatResult {
  return processGolemAttacks(
    activeGolems,
    golemDesigns,
    onDamageDealt,
    golemApplyDamageToRoom,
    enemyElement,
    () => {
      const room = get().currentRoom;
      const living = room.enemies.filter((e) => e.hp > 0);
      if (living.length === 0) return null;
      return living.reduce((lowest, e) => (e.hp < lowest.hp ? e : lowest));
    },
    () => {
      const room = get().currentRoom;
      return room.enemies.filter((e) => e.hp > 0);
    },
    (enemyId, effects) => {
      const room = get().currentRoom;
      const updatedEnemies = room.enemies.map((e) => {
        if (e.id !== enemyId) return e;
        const newEffects = [...e.activeEffects];
        for (const effect of effects) {
          const idx = newEffects.findIndex((ae) => ae.type === effect.type);
          if (idx >= 0) {
            newEffects[idx] = {
              ...newEffects[idx],
              remainingDuration: 4,
              magnitude: Math.max(newEffects[idx].magnitude, effect.magnitude),
            };
          } else {
            newEffects.push({ type: effect.type, remainingDuration: 4, magnitude: effect.magnitude, source: 'golem' });
          }
        }
        return { ...e, activeEffects: newEffects };
      });
      set({ currentRoom: { ...room, enemies: updatedEnemies } });
    },
    currentRawMana,
    currentElements,
  );
}
