import { expect } from "@esm-bundle/chai";
import { Explorer } from "../../src/units/Explorer.js";

// Mock Class Definitions
const CLASS_VANGUARD = {
  id: "CLASS_VANGUARD",
  base_stats: { health: 100, attack: 10, speed: 5 },
  growth_rates: { health: 10, attack: 1 },
};

const CLASS_TINKER = {
  id: "CLASS_TINKER",
  base_stats: { health: 80, attack: 8, speed: 7 },
  growth_rates: { health: 5, attack: 2 },
};

describe("Unit: Explorer Class Logic", () => {
  it("CoA 1: Should initialize with base stats from definition", () => {
    const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);

    expect(hero.baseStats.health).to.equal(100);
    expect(hero.baseStats.attack).to.equal(10);
    expect(hero.classMastery["CLASS_VANGUARD"]).to.exist;
    expect(hero.classMastery["CLASS_VANGUARD"].level).to.equal(1);
  });

  it("CoA 2: Should calculate stats based on Level Growth", () => {
    const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);

    // Manually level up to 3
    hero.classMastery["CLASS_VANGUARD"].level = 3;
    hero.recalculateBaseStats(CLASS_VANGUARD);

    // Level 3 means 2 level-ups.
    // Health: 100 + (10 * 2) = 120
    // Attack: 10 + (1 * 2) = 12
    expect(hero.baseStats.health).to.equal(120);
    expect(hero.baseStats.attack).to.equal(12);
  });

  it("CoA 3: changeClass should switch stats and persist old progress", () => {
    const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);

    // Level up Vanguard
    hero.classMastery["CLASS_VANGUARD"].level = 5;
    hero.recalculateBaseStats(CLASS_VANGUARD);
    expect(hero.baseStats.health).to.equal(140); // 100 + 40

    // Switch to Tinker (New Job)
    hero.changeClass("CLASS_TINKER", CLASS_TINKER);

    // Should have Level 1 Tinker Stats
    expect(hero.activeClassId).to.equal("CLASS_TINKER");
    expect(hero.baseStats.health).to.equal(80); // Base Tinker

    // Verify Vanguard history is saved
    expect(hero.classMastery["CLASS_VANGUARD"].level).to.equal(5);
  });

  it("CoA 4: Switching BACK to old class should restore high stats", () => {
    const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
    hero.classMastery["CLASS_VANGUARD"].level = 5;

    // Switch Away
    hero.changeClass("CLASS_TINKER", CLASS_TINKER);

    // Switch Back
    hero.changeClass("CLASS_VANGUARD", CLASS_VANGUARD);

    // Should be back to Level 5 Stats
    expect(hero.baseStats.health).to.equal(140);
  });

  describe("recalculateStats with Skill Tree", () => {
    it("should apply skill tree stat boosts to maxHealth", () => {
      const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
      hero.recalculateBaseStats(CLASS_VANGUARD);
      hero.maxHealth = hero.baseStats.health;
      hero.currentHealth = hero.maxHealth;

      // Initial health should be 100
      expect(hero.maxHealth).to.equal(100);

      // Create skill tree with health boost
      const treeDef = {
        nodes: {
          ROOT: {
            id: "ROOT",
            type: "STAT_BOOST",
            data: { stat: "health", value: 10 },
          },
        },
      };

      // Unlock the node
      hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ROOT"];

      // Recalculate stats with tree definition
      hero.recalculateStats(null, treeDef);

      // Health should be increased by 10
      expect(hero.maxHealth).to.equal(110);
    });

    it("should apply multiple skill tree stat boosts", () => {
      const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
      hero.recalculateBaseStats(CLASS_VANGUARD);
      hero.maxHealth = hero.baseStats.health;
      hero.currentHealth = hero.maxHealth;

      const treeDef = {
        nodes: {
          ROOT: {
            id: "ROOT",
            type: "STAT_BOOST",
            data: { stat: "health", value: 10 },
          },
          NODE_2: {
            id: "NODE_2",
            type: "STAT_BOOST",
            data: { stat: "health", value: 5 },
          },
        },
      };

      // Unlock both nodes
      hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ROOT", "NODE_2"];

      hero.recalculateStats(null, treeDef);

      // Health should be increased by 15 (10 + 5)
      expect(hero.maxHealth).to.equal(115);
    });

    it("should only apply stat boosts from unlocked nodes", () => {
      const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
      hero.recalculateBaseStats(CLASS_VANGUARD);
      hero.maxHealth = hero.baseStats.health;
      hero.currentHealth = hero.maxHealth;

      const treeDef = {
        nodes: {
          ROOT: {
            id: "ROOT",
            type: "STAT_BOOST",
            data: { stat: "health", value: 10 },
          },
          LOCKED_NODE: {
            id: "LOCKED_NODE",
            type: "STAT_BOOST",
            data: { stat: "health", value: 20 },
          },
        },
      };

      // Only unlock ROOT, not LOCKED_NODE
      hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ROOT"];

      hero.recalculateStats(null, treeDef);

      // Should only get boost from ROOT (10), not LOCKED_NODE (20)
      expect(hero.maxHealth).to.equal(110);
    });

    it("should apply stat boosts to non-health stats", () => {
      const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
      hero.recalculateBaseStats(CLASS_VANGUARD);

      const treeDef = {
        nodes: {
          ATTACK_BOOST: {
            id: "ATTACK_BOOST",
            type: "STAT_BOOST",
            data: { stat: "attack", value: 5 },
          },
        },
      };

      hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ATTACK_BOOST"];

      // Note: recalculateStats doesn't return stats, but we can verify it was called
      // The actual stat application is tested through CharacterSheet UI tests
      hero.recalculateStats(null, treeDef);

      // Verify the method completed without error
      expect(hero.maxHealth).to.exist;
    });

    it("should update currentHealth proportionally when maxHealth changes", () => {
      const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
      hero.recalculateBaseStats(CLASS_VANGUARD);
      hero.maxHealth = 100;
      hero.currentHealth = 50; // 50% health

      const treeDef = {
        nodes: {
          ROOT: {
            id: "ROOT",
            type: "STAT_BOOST",
            data: { stat: "health", value: 20 },
          },
        },
      };

      hero.classMastery["CLASS_VANGUARD"].unlockedNodes = ["ROOT"];

      hero.recalculateStats(null, treeDef);

      // maxHealth should be 120 (100 + 20)
      expect(hero.maxHealth).to.equal(120);
      // currentHealth should be proportionally adjusted (50% of 120 = 60)
      expect(hero.currentHealth).to.equal(60);
    });

    it("should handle treeDef with no unlocked nodes", () => {
      const hero = new Explorer("p1", "Hero", "CLASS_VANGUARD", CLASS_VANGUARD);
      hero.recalculateBaseStats(CLASS_VANGUARD);
      hero.maxHealth = hero.baseStats.health;
      hero.currentHealth = hero.maxHealth;

      const treeDef = {
        nodes: {
          ROOT: {
            id: "ROOT",
            type: "STAT_BOOST",
            data: { stat: "health", value: 10 },
          },
        },
      };

      // No unlocked nodes
      hero.classMastery["CLASS_VANGUARD"].unlockedNodes = [];

      hero.recalculateStats(null, treeDef);

      // Health should remain unchanged
      expect(hero.maxHealth).to.equal(100);
    });
  });
});
