// ─── DoT/Debuff Runtime (spec §6) ─────────────────────────────────────────────
// Handles on-hit effect application and DoT tick processing for combat.

import { SPELLS_DEF } from '../constants';
import type { CombatStore, CombatState } from './combat-state.types';
import type { ActiveEffect, EnemyState } from '../types';
import type { SpellOnHitEffect } from '../types/spells';

const DOT_EFFECT_TYPES = new Set(['burn', 'poison', 'bleed']);

/**
 * Apply an on-hit effect from a spell to the current room's primary enemy.
 * Called after a successful spell hit in processCombatTick.
 * spec §6.2
 */
export function applyOnHitEffect(
  get: () => CombatStore,
  set: (state: Partial<CombatState>) => void,
  spellId: string,
  logMessages: string[],
): void {
  const spellDef = SPELLS_DEF[spellId];
  if (!spellDef?.onHitEffect) return;

  const onHit = spellDef.onHitEffect as SpellOnHitEffect;
  if (onHit.applyChance !== undefined && Math.random() > onHit.applyChance) return;

  const state = get();
  const room = state.currentRoom;
  if (!room || room.enemies.length === 0) return;

  // Apply to the first living enemy
  const targetIdx = room.enemies.findIndex(e => e.hp > 0);
  if (targetIdx === -1) return;

  const target = room.enemies[targetIdx];
  const effect: ActiveEffect = {
    type: onHit.type,
    remainingDuration: onHit.duration,
    magnitude: onHit.magnitude,
    source: 'spell',
    bypassArmor: onHit.bypassArmor,
    bypassBarrier: onHit.bypassBarrier,
  };

  const updatedEnemies = [...room.enemies];
  updatedEnemies[targetIdx] = {
    ...target,
    activeEffects: [...target.activeEffects, effect],
  };

  set({ currentRoom: { ...room, enemies: updatedEnemies } });
  logMessages.push(`${target.name} afflicted with ${onHit.type}`);
}

/**
 * Process one tick of all active effects on all enemies in the current room.
 * Called after all weapon/golem attacks in processCombatTick.
 * spec §6.3
 * Returns total DoT damage dealt (to subtract from floorHP).
 */
export function processDoTPhase(
  get: () => CombatStore,
  set: (state: Partial<CombatState>) => void,
  applyEnemyDefenses: (
    dmg: number,
    enemy: EnemyState | null,
    roomType: string,
    addLog: (msg: string) => void,
    bypassArmor?: boolean,
    bypassBarrier?: boolean,
  ) => number,
  logMessages: string[],
): number {
  const state = get();
  const room = state.currentRoom;
  if (!room || room.enemies.length === 0) return 0;

  let totalDoTDamage = 0;
  const updatedEnemies: EnemyState[] = [];

  for (const enemy of room.enemies) {
    if (enemy.hp <= 0) {
      updatedEnemies.push(enemy);
      continue;
    }

    let enemyHp = enemy.hp;
    const remainingEffects: ActiveEffect[] = [];
    let totalCorrodeMagnitude = 0;

    for (const effect of enemy.activeEffects) {
      if (DOT_EFFECT_TYPES.has(effect.type)) {
        // DoT: burn, poison, bleed (spec §6.3)
        const dmg = effect.magnitude;
        let dotFinalDmg: number;
        if (effect.bypassArmor) {
          // AC-13: bypass armor — apply directly to HP, skip all defenses
          dotFinalDmg = dmg;
        } else if (effect.bypassBarrier) {
          // Bypass barrier: skip barrier but still apply armor
          dotFinalDmg = applyEnemyDefenses(dmg, enemy, room.roomType, () => {}, false, true);
        } else {
          // Normal: apply full defense pipeline (dodge → barrier → armor)
          dotFinalDmg = applyEnemyDefenses(dmg, enemy, room.roomType, () => {});
        }
        enemyHp = Math.max(0, enemyHp - dotFinalDmg);
        totalDoTDamage += dotFinalDmg;
      } else if (effect.type === 'curse') {
        // Curse: amplifies incoming damage (tracked on enemy, applied next tick)
        // No immediate HP effect — curse multiplier is stored on the enemy
      } else if (effect.type === 'armor_corrode') {
        // Armor corrode: accumulate magnitude for temporary reduction (spec §6.3, D-31 fix)
        totalCorrodeMagnitude += effect.magnitude;
      }
      // freeze, slow, blind: soft CC — no HP effect, just tracked

      // Decrement duration
      const newDuration = effect.remainingDuration - 1;
      if (newDuration > 0) {
        remainingEffects.push({ ...effect, remainingDuration: newDuration });
      }
    }

    // Compute effectiveArmor from base armor minus active corrode effects (temporary)
    const effectiveArmor = Math.max(0, enemy.armor - totalCorrodeMagnitude);

    updatedEnemies.push({
      ...enemy,
      hp: enemyHp,
      effectiveArmor,
      activeEffects: remainingEffects,
    });
  }

  set({ currentRoom: { ...room, enemies: updatedEnemies } });
  return totalDoTDamage;
}
