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

describe("Systems: Environmental Hazards", function () {
  let turnSystem;
  let grid;
  let unitManager;
  let effectProcessor;
  let unit;
  let mockRegistry;

  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,
        speed: 10,
        movement: 4,
      },
    });

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

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

    effectProcessor = new EffectProcessor(grid, unitManager);
    turnSystem = new TurnSystem(unitManager);
    turnSystem.setHazardContext(grid, effectProcessor);

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

  describe("Integration Point 3: Environmental Hazards", () => {
    it("should apply fire hazard damage when unit starts turn on fire", () => {
      // Place fire hazard at unit's position
      grid.addHazard(unit.position, "HAZARD_FIRE", 3);

      const initialHP = unit.currentHealth;
      const defense = unit.baseStats.defense || 0;
      const expectedDamage = Math.max(0, 5 - defense); // 5 fire damage - defense

      // Start turn (should process hazards)
      turnSystem.startTurn(unit);

      // Unit should have taken fire damage (reduced by defense)
      expect(unit.currentHealth).to.be.lessThanOrEqual(initialHP);
      expect(unit.currentHealth).to.equal(initialHP - expectedDamage);
    });

    it("should apply acid hazard damage when unit starts turn on acid", () => {
      // Place acid hazard at unit's position
      grid.addHazard(unit.position, "HAZARD_ACID", 2);

      const initialHP = unit.currentHealth;
      const defense = unit.baseStats.defense || 0;
      const expectedDamage = Math.max(0, 5 - defense); // 5 acid damage - defense

      // Start turn
      turnSystem.startTurn(unit);

      // Unit should have taken acid damage (reduced by defense)
      expect(unit.currentHealth).to.be.lessThanOrEqual(initialHP);
      expect(unit.currentHealth).to.equal(initialHP - expectedDamage);
    });

    it("should decrement hazard duration after processing", () => {
      // Place hazard with duration 2
      grid.addHazard(unit.position, "HAZARD_FIRE", 2);

      const hazard = grid.getHazardAt(unit.position);
      expect(hazard.duration).to.equal(2);

      // Start turn (should decrement duration)
      turnSystem.startTurn(unit);

      const hazardAfter = grid.getHazardAt(unit.position);
      expect(hazardAfter.duration).to.equal(1);
    });

    it("should remove hazard when duration reaches 0", () => {
      // Place hazard with duration 1
      grid.addHazard(unit.position, "HAZARD_FIRE", 1);

      expect(grid.getHazardAt(unit.position)).to.exist;

      // Start turn (should remove hazard)
      turnSystem.startTurn(unit);

      // Hazard should be removed
      expect(grid.getHazardAt(unit.position)).to.be.undefined;
    });

    it("should not process hazards if unit is not on a hazard tile", () => {
      const initialHP = unit.currentHealth;

      // Start turn without any hazard
      turnSystem.startTurn(unit);

      // Health should be unchanged (except for status effects if any)
      expect(unit.currentHealth).to.equal(initialHP);
    });

    it("should handle unknown hazard types with default damage", () => {
      // Place unknown hazard type
      grid.addHazard(unit.position, "HAZARD_UNKNOWN", 1);

      const initialHP = unit.currentHealth;
      const defense = unit.baseStats.defense || 0;
      const expectedDamage = Math.max(0, 5 - defense); // Default 5 damage - defense

      // Start turn
      turnSystem.startTurn(unit);

      // Unit should still take damage (default 5, reduced by defense)
      if (expectedDamage > 0) {
        expect(unit.currentHealth).to.be.lessThan(initialHP);
      }
      expect(unit.currentHealth).to.equal(initialHP - expectedDamage);
    });

    it("should process hazards before status effects in turn order", () => {
      // Add hazard and status effect
      grid.addHazard(unit.position, "HAZARD_FIRE", 1);
      unit.statusEffects = [
        {
          id: "poison",
          type: "DOT",
          damage: 3,
          duration: 1,
        },
      ];

      const initialHP = unit.currentHealth;
      const defense = unit.baseStats.defense || 0;
      const hazardDamage = Math.max(0, 5 - defense); // 5 fire damage - defense
      const poisonDamage = 3; // Poison damage (not reduced by defense in current implementation)

      // Start turn
      turnSystem.startTurn(unit);

      // Should have taken both hazard damage and poison damage
      expect(unit.currentHealth).to.equal(initialHP - hazardDamage - poisonDamage);
    });
  });
});

