import { expect } from "@esm-bundle/chai";
import { EffectProcessor } from "../../src/systems/EffectProcessor.js";
import { VoxelGrid } from "../../src/grid/VoxelGrid.js";
import { UnitManager } from "../../src/managers/UnitManager.js";
import { SeededRandom } from "../../src/utils/SeededRandom.js";

describe("Systems: EffectProcessor", function () {
  let processor;
  let grid;
  let unitManager;
  let mockRegistry;
  let sourceUnit;
  let targetUnit;

  beforeEach(() => {
    // Create mock registry
    mockRegistry = new Map();
    mockRegistry.set("CLASS_VANGUARD", {
      id: "CLASS_VANGUARD",
      name: "Vanguard",
      type: "EXPLORER",
      base_stats: {
        health: 100,
        attack: 10,
        defense: 5,
        magic: 5,
        speed: 10,
        movement: 4,
      },
    });
    mockRegistry.set("ENEMY_GOBLIN", {
      id: "ENEMY_GOBLIN",
      name: "Goblin",
      type: "ENEMY",
      stats: {
        health: 50,
        attack: 8,
        defense: 3,
        magic: 0,
      },
    });

    unitManager = new UnitManager(mockRegistry);
    grid = new VoxelGrid(20, 5, 20);

    // Create a simple walkable floor at y=1
    for (let x = 0; x < 20; x++) {
      for (let z = 0; z < 20; z++) {
        // Floor at y=0
        grid.setCell(x, 0, z, 1);
        // Air at y=1 (walkable)
        grid.setCell(x, 1, z, 0);
        // Air at y=2 (headroom)
        grid.setCell(x, 2, z, 0);
      }
    }

    processor = new EffectProcessor(grid, unitManager);

    // Create test units
    sourceUnit = unitManager.createUnit("CLASS_VANGUARD", "PLAYER");
    sourceUnit.position = { x: 5, y: 1, z: 5 };
    sourceUnit.currentHealth = 100;
    sourceUnit.maxHealth = 100;
    grid.placeUnit(sourceUnit, sourceUnit.position);

    targetUnit = unitManager.createUnit("ENEMY_GOBLIN", "ENEMY");
    targetUnit.position = { x: 6, y: 1, z: 5 };
    targetUnit.currentHealth = 50;
    targetUnit.maxHealth = 50;
    grid.placeUnit(targetUnit, targetUnit.position);
  });

  describe("Constructor", () => {
    it("should initialize with VoxelGrid and UnitManager", () => {
      expect(processor.voxelGrid).to.equal(grid);
      expect(processor.unitManager).to.equal(unitManager);
      expect(processor.handlers).to.be.instanceOf(Map);
      expect(processor.handlers.size).to.be.greaterThan(0);
    });

    it("should register all handler types", () => {
      expect(processor.handlers.has("DAMAGE")).to.be.true;
      expect(processor.handlers.has("HEAL")).to.be.true;
      expect(processor.handlers.has("APPLY_STATUS")).to.be.true;
      expect(processor.handlers.has("REMOVE_STATUS")).to.be.true;
      expect(processor.handlers.has("PUSH")).to.be.true;
      expect(processor.handlers.has("PULL")).to.be.true;
      expect(processor.handlers.has("TELEPORT")).to.be.true;
    });

    it("should accept optional RNG", () => {
      const rng = new SeededRandom(12345);
      const processorWithRng = new EffectProcessor(grid, unitManager, rng);
      expect(processorWithRng.rng).to.equal(rng);
    });
  });

  describe("CoA 1: Attribute Scaling", () => {
    it("should calculate power with attribute scaling", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
        attribute: "magic",
        scaling: 1.0,
      };

      // Source has magic: 5, so power should be 10 + (5 * 1.0) = 15
      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.amount).to.equal(15 - targetUnit.baseStats.defense); // 15 - 3 = 12
    });

    it("should handle custom scaling multiplier", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
        attribute: "magic",
        scaling: 2.0,
      };

      // Source has magic: 5, so power should be 10 + (5 * 2.0) = 20
      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.amount).to.equal(20 - targetUnit.baseStats.defense); // 20 - 3 = 17
    });

    it("should use base power when no attribute specified", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
      };

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.amount).to.equal(10 - targetUnit.baseStats.defense); // 10 - 3 = 7
    });
  });

  describe("CoA 2: Conditional Logic", () => {
    it("should not execute if target_status condition is not met", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
        condition: {
          target_status: "WET",
        },
      };

      // Target does not have WET status
      targetUnit.statusEffects = [];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Conditions not met");
      expect(targetUnit.currentHealth).to.equal(50); // Health unchanged
    });

    it("should execute if target_status condition is met", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
        condition: {
          target_status: "WET",
        },
      };

      // Target has WET status
      targetUnit.statusEffects = [{ id: "WET", type: "STATUS", duration: 3 }];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.currentHealth).to.be.lessThan(50); // Health changed
    });

    it("should not execute if hp_threshold condition is not met", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
        condition: {
          hp_threshold: 0.3, // 30% HP
        },
      };

      // Target has 50/50 HP = 100%, which is > 30%
      targetUnit.currentHealth = 50;
      targetUnit.maxHealth = 50;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Conditions not met");
    });

    it("should execute if hp_threshold condition is met", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
        condition: {
          hp_threshold: 0.3, // 30% HP
        },
      };

      // Target has 10/50 HP = 20%, which is < 30%
      targetUnit.currentHealth = 10;
      targetUnit.maxHealth = 50;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.currentHealth).to.be.lessThan(10); // Health changed
    });

    it("should execute if no conditions are specified", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
      };

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
    });
  });

  describe("CoA 3: State Mutation", () => {
    it("should add status effect to target's statusEffects array", () => {
      const effectDef = {
        type: "APPLY_STATUS",
        status_id: "BURN",
        duration: 3,
      };

      targetUnit.statusEffects = [];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.statusEffects).to.have.lengthOf(1);
      expect(targetUnit.statusEffects[0].id).to.equal("BURN");
      expect(targetUnit.statusEffects[0].duration).to.equal(3);
      expect(targetUnit.statusEffects[0].type).to.equal("STATUS");
    });

    it("should refresh duration if status already exists", () => {
      const effectDef = {
        type: "APPLY_STATUS",
        status_id: "BURN",
        duration: 5,
      };

      // Target already has BURN with duration 2
      targetUnit.statusEffects = [
        { id: "BURN", type: "STATUS", duration: 2 },
      ];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.statusEffects).to.have.lengthOf(1);
      expect(targetUnit.statusEffects[0].duration).to.equal(5); // Refreshed to max
    });

    it("should not reduce duration if existing is longer", () => {
      const effectDef = {
        type: "APPLY_STATUS",
        status_id: "BURN",
        duration: 2,
      };

      // Target already has BURN with duration 5
      targetUnit.statusEffects = [
        { id: "BURN", type: "STATUS", duration: 5 },
      ];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.statusEffects[0].duration).to.equal(5); // Kept longer duration
    });
  });

  describe("CoA 4: Physics Safety", () => {
    it("should not move unit into solid terrain on PUSH", () => {
      const effectDef = {
        type: "PUSH",
        force: 2,
      };

      // Place a wall behind the target
      const wallPos = { x: 7, y: 1, z: 5 };
      grid.setCell(wallPos.x, wallPos.y, wallPos.z, 10); // Wall ID

      const oldPosition = { ...targetUnit.position };

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Push/Pull blocked by solid terrain");
      expect(targetUnit.position.x).to.equal(oldPosition.x);
      expect(targetUnit.position.z).to.equal(oldPosition.z);
    });

    it("should successfully push unit when path is clear", () => {
      const effectDef = {
        type: "PUSH",
        force: 1,
      };

      const oldPosition = { ...targetUnit.position };

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      // Position should change (at least one coordinate)
      expect(
        targetUnit.position.x !== oldPosition.x ||
          targetUnit.position.z !== oldPosition.z
      ).to.be.true;
      // Verify the unit was actually moved in the grid
      expect(grid.getUnitAt(targetUnit.position)).to.equal(targetUnit);
    });
  });

  describe("Handler: DAMAGE", () => {
    it("should reduce target's currentHealth", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 20,
      };

      const initialHealth = targetUnit.currentHealth;
      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.type).to.equal("DAMAGE");
      expect(result.data.amount).to.be.greaterThan(0);
      expect(targetUnit.currentHealth).to.be.lessThan(initialHealth);
      expect(targetUnit.currentHealth).to.equal(
        initialHealth - result.data.amount
      );
    });

    it("should apply defense reduction", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
      };

      const defense = targetUnit.baseStats.defense; // 3
      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.amount).to.equal(10 - defense); // 7
    });

    it("should not reduce health below 0", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 1000,
      };

      targetUnit.currentHealth = 10;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.currentHealth).to.equal(0);
    });

    it("should return error if target is not a Unit", () => {
      const effectDef = {
        type: "DAMAGE",
        power: 10,
      };

      const position = { x: 5, y: 1, z: 5 };
      const result = processor.process(effectDef, sourceUnit, position);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Damage target must be a Unit");
    });
  });

  describe("Handler: HEAL", () => {
    it("should increase target's currentHealth", () => {
      const effectDef = {
        type: "HEAL",
        power: 20,
      };

      targetUnit.currentHealth = 30;
      const initialHealth = targetUnit.currentHealth;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.type).to.equal("HEAL");
      expect(result.data.amount).to.be.greaterThan(0);
      expect(targetUnit.currentHealth).to.be.greaterThan(initialHealth);
    });

    it("should not exceed maxHealth", () => {
      const effectDef = {
        type: "HEAL",
        power: 1000,
      };

      targetUnit.currentHealth = 40;
      targetUnit.maxHealth = 50;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.currentHealth).to.equal(50); // Capped at maxHealth
      expect(result.data.amount).to.equal(10); // Only healed 10
    });

    it("should support attribute scaling", () => {
      const effectDef = {
        type: "HEAL",
        power: 10,
        attribute: "magic",
        scaling: 1.0,
      };

      targetUnit.currentHealth = 30;
      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      // Should heal 10 + (5 * 1.0) = 15, but capped at maxHealth
      expect(targetUnit.currentHealth).to.be.greaterThan(30);
    });
  });

  describe("Handler: APPLY_STATUS", () => {
    it("should apply status with chance roll", () => {
      const effectDef = {
        type: "APPLY_STATUS",
        status_id: "STUN",
        duration: 2,
        chance: 1.0, // 100% chance
      };

      targetUnit.statusEffects = [];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.statusEffects).to.have.lengthOf(1);
      expect(targetUnit.statusEffects[0].id).to.equal("STUN");
    });

    it("should fail if chance roll fails", () => {
      const effectDef = {
        type: "APPLY_STATUS",
        status_id: "STUN",
        duration: 2,
        chance: 0.0, // 0% chance
      };

      targetUnit.statusEffects = [];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Status effect failed chance roll");
      expect(targetUnit.statusEffects).to.have.lengthOf(0);
    });

    it("should use default chance of 1.0 if not specified", () => {
      const effectDef = {
        type: "APPLY_STATUS",
        status_id: "POISON",
        duration: 3,
        // No chance specified
      };

      targetUnit.statusEffects = [];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.statusEffects).to.have.lengthOf(1);
    });

    it("should return error if status_id is missing", () => {
      const effectDef = {
        type: "APPLY_STATUS",
        duration: 2,
        // Missing status_id
      };

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Status effect missing status_id");
    });
  });

  describe("Handler: REMOVE_STATUS", () => {
    it("should remove status effect from target", () => {
      const effectDef = {
        type: "REMOVE_STATUS",
        status_id: "BURN",
      };

      targetUnit.statusEffects = [
        { id: "BURN", type: "STATUS", duration: 3 },
        { id: "POISON", type: "STATUS", duration: 2 },
      ];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(targetUnit.statusEffects).to.have.lengthOf(1);
      expect(targetUnit.statusEffects[0].id).to.equal("POISON");
    });

    it("should return error if status not found", () => {
      const effectDef = {
        type: "REMOVE_STATUS",
        status_id: "BURN",
      };

      targetUnit.statusEffects = [];

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Status effect not found on target");
    });
  });

  describe("Handler: PUSH", () => {
    it("should push unit away from source", () => {
      const effectDef = {
        type: "PUSH",
        force: 2,
      };

      const oldX = targetUnit.position.x;
      const oldZ = targetUnit.position.z;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.type).to.equal("PUSH");
      // Target should be pushed away from source (5,5) -> (6,5)
      // Direction is (1, 0), so pushed to (8, 5) with force 2
      expect(targetUnit.position.x).to.be.greaterThan(oldX);
    });

    it("should not push if destination is occupied", () => {
      const effectDef = {
        type: "PUSH",
        force: 1,
      };

      // Place another unit at the push destination
      const otherUnit = unitManager.createUnit("ENEMY_GOBLIN", "ENEMY");
      const pushDest = { x: 7, y: 1, z: 5 };
      grid.placeUnit(otherUnit, pushDest);

      const oldPosition = { ...targetUnit.position };
      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Push/Pull destination is occupied");
      expect(targetUnit.position.x).to.equal(oldPosition.x);
    });
  });

  describe("Handler: PULL", () => {
    it("should pull unit toward source", () => {
      const effectDef = {
        type: "PULL",
        force: 1,
      };

      // Move target further away first
      targetUnit.position = { x: 8, y: 1, z: 5 };
      grid.placeUnit(targetUnit, targetUnit.position);

      const oldX = targetUnit.position.x;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.type).to.equal("PULL");
      // Target should be pulled toward source (5,5) from (8,5)
      // Direction is (-1, 0), so pulled to (7, 5) with force 1
      expect(targetUnit.position.x).to.be.lessThan(oldX);
    });
  });

  describe("Handler: TELEPORT", () => {
    it("should teleport unit to valid destination", () => {
      const destination = { x: 10, y: 1, z: 10 };

      const effectDef = {
        type: "TELEPORT",
        destination: "TARGET",
      };

      const result = processor.process(effectDef, sourceUnit, destination);

      expect(result.success).to.be.true;
      expect(result.data.type).to.equal("TELEPORT");
      expect(sourceUnit.position.x).to.equal(10);
      expect(sourceUnit.position.z).to.equal(10);
    });

    it("should not teleport to solid terrain", () => {
      const destination = { x: 10, y: 1, z: 10 };
      grid.setCell(10, 1, 10, 10); // Place a wall

      const effectDef = {
        type: "TELEPORT",
        destination: "TARGET",
      };

      const oldPosition = { ...sourceUnit.position };
      const result = processor.process(effectDef, sourceUnit, destination);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Teleport destination is solid");
      expect(sourceUnit.position.x).to.equal(oldPosition.x);
    });

    it("should not teleport to occupied position", () => {
      const destination = { x: 6, y: 1, z: 5 }; // Where targetUnit is

      const effectDef = {
        type: "TELEPORT",
        destination: "TARGET",
      };

      const oldPosition = { ...sourceUnit.position };
      const result = processor.process(effectDef, sourceUnit, destination);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Teleport destination is occupied");
      expect(sourceUnit.position.x).to.equal(oldPosition.x);
    });

    it("should teleport behind target when destination is BEHIND_TARGET", () => {
      // Source at (5,5), target at (6,5)
      // Behind target would be (7,5)
      const effectDef = {
        type: "TELEPORT",
        destination: "BEHIND_TARGET",
      };

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(sourceUnit.position.x).to.equal(7);
      expect(sourceUnit.position.z).to.equal(5);
    });
  });

  describe("Process Method", () => {
    it("should return error for invalid effect definition", () => {
      const result = processor.process(null, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Invalid effect definition");
    });

    it("should return error for unknown effect type", () => {
      const effectDef = {
        type: "UNKNOWN_TYPE",
        power: 10,
      };

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Unknown effect type: UNKNOWN_TYPE");
    });

    it("should handle handler execution errors gracefully", () => {
      // Create a processor with a broken handler
      const brokenProcessor = new EffectProcessor(grid, unitManager);
      brokenProcessor.handlers.set("DAMAGE", () => {
        throw new Error("Handler error");
      });

      const effectDef = {
        type: "DAMAGE",
        power: 10,
      };

      const result = brokenProcessor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.false;
      expect(result.error).to.equal("Handler error");
    });
  });

  describe("Handler: CHAIN_DAMAGE", () => {
    it("should apply damage to primary target and chain to nearby enemies", () => {
      // Create additional enemy units for chaining
      const enemy2 = unitManager.createUnit("ENEMY_GOBLIN", "ENEMY");
      enemy2.position = { x: 7, y: 1, z: 5 }; // Distance 1 from targetUnit
      enemy2.currentHealth = 50;
      enemy2.maxHealth = 50;
      grid.placeUnit(enemy2, enemy2.position);

      const enemy3 = unitManager.createUnit("ENEMY_GOBLIN", "ENEMY");
      enemy3.position = { x: 8, y: 1, z: 5 }; // Distance 2 from targetUnit
      enemy3.currentHealth = 50;
      enemy3.maxHealth = 50;
      grid.placeUnit(enemy3, enemy3.position);

      const effectDef = {
        type: "CHAIN_DAMAGE",
        power: 10,
        bounces: 2,
        chainRange: 3,
        decay: 0.5,
      };

      const initialPrimaryHP = targetUnit.currentHealth;
      const initialEnemy2HP = enemy2.currentHealth;
      const initialEnemy3HP = enemy3.currentHealth;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      expect(result.data.type).to.equal("CHAIN_DAMAGE");
      expect(result.data.chainTargets.length).to.be.greaterThan(0);

      // Primary target should have taken damage
      expect(targetUnit.currentHealth).to.be.lessThan(initialPrimaryHP);

      // Chained targets should have taken reduced damage
      if (result.data.chainTargets.includes(enemy2.id)) {
        expect(enemy2.currentHealth).to.be.lessThan(initialEnemy2HP);
      }
    });

    it("should apply double damage to targets with synergy trigger status", () => {
      // Create enemy with WET status
      const wetEnemy = unitManager.createUnit("ENEMY_GOBLIN", "ENEMY");
      wetEnemy.position = { x: 7, y: 1, z: 5 };
      wetEnemy.currentHealth = 50;
      wetEnemy.maxHealth = 50;
      wetEnemy.statusEffects = [{ id: "STATUS_WET", type: "STATUS", duration: 2 }];
      grid.placeUnit(wetEnemy, wetEnemy.position);

      const effectDef = {
        type: "CHAIN_DAMAGE",
        power: 10,
        bounces: 1,
        chainRange: 3,
        decay: 0.5,
        synergy_trigger: "STATUS_WET",
      };

      const initialWetHP = wetEnemy.currentHealth;

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;

      // WET enemy should have taken double damage (10 * 0.5 * 2 = 10, minus defense)
      // Without synergy it would be (10 * 0.5 = 5, minus defense)
      const defense = wetEnemy.baseStats.defense || 0;
      const expectedRegularDamage = Math.max(0, 10 * 0.5 - defense); // 5 - defense
      const expectedSynergyDamage = Math.max(0, 10 * 0.5 * 2 - defense); // 10 - defense
      
      const actualDamage = initialWetHP - wetEnemy.currentHealth;
      expect(wetEnemy.currentHealth).to.be.lessThan(initialWetHP);
      // Should have taken synergy damage (double), which is more than regular damage
      expect(actualDamage).to.be.greaterThan(expectedRegularDamage);
      expect(actualDamage).to.equal(expectedSynergyDamage);
    });

    it("should respect bounce limit", () => {
      // Create multiple enemies
      const enemies = [];
      for (let i = 0; i < 5; i++) {
        const enemy = unitManager.createUnit("ENEMY_GOBLIN", "ENEMY");
        enemy.position = { x: 6 + i, y: 1, z: 5 };
        enemy.currentHealth = 50;
        enemy.maxHealth = 50;
        grid.placeUnit(enemy, enemy.position);
        enemies.push(enemy);
      }

      const effectDef = {
        type: "CHAIN_DAMAGE",
        power: 10,
        bounces: 2, // Only 2 bounces
        chainRange: 10,
        decay: 0.5,
      };

      const result = processor.process(effectDef, sourceUnit, targetUnit);

      expect(result.success).to.be.true;
      // Should only chain to 2 enemies (bounces limit)
      expect(result.data.chainTargets.length).to.be.at.most(2);
    });
  });
});

