import { gameStateManager } from "./core/GameStateManager.js";

/** @type {HTMLElement | null} */
const gameViewport = document.querySelector("game-viewport");
/** @type {HTMLElement | null} */
const teamBuilder = document.querySelector("team-builder");
/** @type {HTMLElement | null} */
const mainMenu = document.getElementById("main-menu");
/** @type {HTMLElement | null} */
const hubScreen = document.querySelector("hub-screen");
/** @type {HTMLElement | null} */
const btnNewRun = document.getElementById("btn-start");
/** @type {HTMLElement | null} */
const btnContinue = document.getElementById("btn-load");
/** @type {HTMLElement | null} */
const loadingOverlay = document.getElementById("loading-overlay");
/** @type {HTMLElement | null} */
const loadingMessage = document.getElementById("loading-message");
/** @type {HTMLElement | null} */
const uiLayer = document.getElementById("ui-layer");

// --- Event Listeners ---

// Character Sheet Integration
let currentCharacterSheet = null;

window.addEventListener("open-character-sheet", async (e) => {
  let {
    unit,
    unitId,
    readOnly = false,
    inventory = [],
    skillTree = null,
  } = e.detail;

  // Resolve unit from ID if needed
  if (!unit && unitId && gameStateManager.gameLoop?.unitManager) {
    unit = gameStateManager.gameLoop.unitManager.getUnitById(unitId);
  }

  if (!unit) {
    console.warn("open-character-sheet event missing unit or unitId");
    return;
  }

  // If character sheet is already open, close it (toggle behavior)
  if (currentCharacterSheet) {
    currentCharacterSheet.remove();
    currentCharacterSheet = null;
    // Resume GameLoop if it was paused
    if (gameStateManager.gameLoop && gameStateManager.gameLoop.isPaused) {
      gameStateManager.gameLoop.resume();
    }
    return;
  }

  // Pause GameLoop if in combat
  let wasPaused = false;
  if (
    gameStateManager.gameLoop &&
    gameStateManager.currentState === "STATE_COMBAT"
  ) {
    wasPaused = gameStateManager.gameLoop.isPaused;
    if (!wasPaused && gameStateManager.gameLoop.isRunning) {
      gameStateManager.gameLoop.pause();
    }
  }

  // Dynamically import CharacterSheet component
  const { CharacterSheet } = await import("./ui/components/character-sheet.js");

  // Generate skill tree using SkillTreeFactory if available
  // Use provided skillTree if available (e.g., from barracks), otherwise generate
  if (
    !skillTree &&
    gameStateManager.gameLoop?.classRegistry &&
    unit.activeClassId
  ) {
    try {
      const { SkillTreeFactory } = await import(
        "./factories/SkillTreeFactory.js"
      );

      // Load skill tree template
      const templateResponse = await fetch(
        "assets/data/skill_trees/template_standard_30.json"
      );
      if (templateResponse.ok) {
        const template = await templateResponse.json();
        const templateRegistry = { [template.id]: template };

        // Get class definition
        const classDef = gameStateManager.gameLoop.classRegistry.get(
          unit.activeClassId
        );

        if (classDef && classDef.skillTreeData) {
          // Get skill registry - import it directly
          const { skillRegistry } = await import("./managers/SkillRegistry.js");

          // Convert Map to object for SkillTreeFactory
          const skillMap = Object.fromEntries(skillRegistry.skills);

          // Create factory and generate tree
          const factory = new SkillTreeFactory(templateRegistry, skillMap);
          skillTree = factory.createTree(classDef);
        }
      }
    } catch (error) {
      console.warn(
        "Failed to load skill tree template, using fallback:",
        error
      );
    }
  }

  // Create character sheet
  const characterSheet = document.createElement("character-sheet");
  characterSheet.unit = unit;
  characterSheet.readOnly = readOnly;
  characterSheet.inventory = inventory;
  characterSheet.gameMode =
    gameStateManager.currentState === "STATE_COMBAT" ? "DUNGEON" : "HUB";
  // Use provided skillTree if available (from barracks), otherwise use generated one
  characterSheet.treeDef = skillTree || null; // Pass generated tree
  // Pass inventoryManager - use hubInventoryManager in Hub mode, gameLoop's in combat
  if (
    gameStateManager.currentState === "STATE_COMBAT" &&
    gameStateManager.gameLoop?.inventoryManager
  ) {
    characterSheet.inventoryManager =
      gameStateManager.gameLoop.inventoryManager;
  } else if (gameStateManager.hubInventoryManager) {
    characterSheet.inventoryManager = gameStateManager.hubInventoryManager;
  }

  // Handle close event
  const handleClose = () => {
    characterSheet.remove();
    currentCharacterSheet = null;
    // Resume GameLoop if it was paused
    if (
      !wasPaused &&
      gameStateManager.gameLoop &&
      gameStateManager.gameLoop.isPaused
    ) {
      gameStateManager.gameLoop.resume();
    }
  };

  // Handle equip-item event (update unit equipment)
  const handleEquipItem = (event) => {
    const { unitId, slot, item, oldItem } = event.detail;
    // Equipment is already updated in the component
    // This event can be used for persistence or other side effects
    console.log(`Equipped ${item.name} to ${slot} slot for unit ${unitId}`);
  };

  // Handle unlock-request event from SkillTreeUI
  const handleUnlockRequest = (event) => {
    const { nodeId, cost } = event.detail;
    const mastery = unit.classMastery?.[unit.activeClassId];

    if (!mastery) {
      console.warn("No mastery data found for unit");
      return;
    }

    if (mastery.skillPoints < cost) {
      console.warn("Insufficient skill points");
      return;
    }

    // Deduct skill points and unlock node
    mastery.skillPoints -= cost;
    if (!mastery.unlockedNodes) {
      mastery.unlockedNodes = [];
    }
    if (!mastery.unlockedNodes.includes(nodeId)) {
      mastery.unlockedNodes.push(nodeId);
    }

    // Trigger update in character sheet
    characterSheet.requestUpdate();

    console.log(`Unlocked node ${nodeId} for ${cost} skill points`);
  };

  // Handle skill-unlocked event to refresh combat HUD
  const handleSkillUnlocked = (event) => {
    const { unitId } = event.detail;
    // If we're in combat and the gameLoop exists, update combat state to refresh the HUD
    if (
      gameStateManager?.gameLoop &&
      gameStateManager.currentState === "STATE_COMBAT"
    ) {
      // Update combat state to refresh the HUD with newly unlocked skills
      gameStateManager.gameLoop.updateCombatState().catch(console.error);
    }
  };

  characterSheet.addEventListener("close", handleClose);
  characterSheet.addEventListener("equip-item", handleEquipItem);
  characterSheet.addEventListener("unlock-request", handleUnlockRequest);
  characterSheet.addEventListener("skill-unlocked", handleSkillUnlocked);

  // Append to document body - dialog will handle its own display
  document.body.appendChild(characterSheet);
  currentCharacterSheet = characterSheet;
});

window.addEventListener("gamestate-changed", async (e) => {
  const { newState } = e.detail;
  console.log("gamestate-changed", newState);
  switch (newState) {
    case "STATE_MAIN_MENU":
      // Check if we should show hub or main menu
      const hasRoster = gameStateManager.rosterManager.roster.length > 0;
      const hasCompletedMissions =
        gameStateManager.missionManager.completedMissions.size > 0;
      const shouldShowHub = hasRoster || hasCompletedMissions;
      loadingMessage.textContent = shouldShowHub
        ? "INITIALIZING HUB..."
        : "INITIALIZING MAIN MENU...";
      break;
    case "STATE_TEAM_BUILDER":
      loadingMessage.textContent = "INITIALIZING TEAM BUILDER...";
      break;
    case "STATE_DEPLOYMENT":
    case "STATE_COMBAT":
      import("./ui/game-viewport.js");
      loadingMessage.textContent = "INITIALIZING GAME ENGINE...";
      break;
  }

  loadingOverlay.toggleAttribute("hidden", false);
  mainMenu.toggleAttribute("hidden", true);
  gameViewport.toggleAttribute("hidden", true);
  teamBuilder.toggleAttribute("hidden", true);
  if (hubScreen) {
    hubScreen.toggleAttribute("hidden", true);
  }
  switch (newState) {
    case "STATE_MAIN_MENU":
      // Check if we should show hub or main menu
      const hasRoster = gameStateManager.rosterManager.roster.length > 0;
      const hasCompletedMissions =
        gameStateManager.missionManager.completedMissions.size > 0;
      const shouldShowHub = hasRoster || hasCompletedMissions;

      if (shouldShowHub) {
        // Load HubScreen dynamically
        await import("./ui/screens/hub-screen.js");
        await import("./ui/components/mission-board.js");
        const hub = document.querySelector("hub-screen");
        if (hub) {
          hub.toggleAttribute("hidden", false);
        } else {
          // Create hub-screen if it doesn't exist in HTML
          const hubElement = document.createElement("hub-screen");
          document.body.appendChild(hubElement);
          hubElement.toggleAttribute("hidden", false);
        }
      } else {
        // Show main menu for new players
        mainMenu.toggleAttribute("hidden", false);
      }
      break;
    case "STATE_TEAM_BUILDER":
      await import("./ui/team-builder.js");
      // Check if we have any roster (not just deployable units)
      const rosterExists = gameStateManager.rosterManager.roster.length > 0;
      const deployableUnits =
        gameStateManager.rosterManager.getDeployableUnits();

      if (rosterExists) {
        // We have a roster, use ROSTER mode (even if no deployable units)
        // Setting availablePool will trigger willUpdate() which calls _initializeData()
        teamBuilder.availablePool = deployableUnits || [];
        teamBuilder._poolExplicitlySet = true;
        console.log(
          "TeamBuilder: Populated with roster units",
          deployableUnits?.length || 0,
          "deployable out of",
          gameStateManager.rosterManager.roster.length,
          "total"
        );
      } else {
        // No roster yet, use draft mode
        teamBuilder.availablePool = [];
        teamBuilder._poolExplicitlySet = false;
        console.log("TeamBuilder: No roster available, using draft mode");
      }
      teamBuilder.toggleAttribute("hidden", false);
      break;
    case "STATE_DEPLOYMENT":
    case "STATE_COMBAT":
      await import("./ui/game-viewport.js");
      gameViewport.toggleAttribute("hidden", false);
      // Squad will be updated by game-viewport's #updateSquad() method
      // which listens to gamestate-changed events
      break;
  }
  loadingOverlay.toggleAttribute("hidden", true);
});

window.addEventListener("save-check-complete", (e) => {
  if (e.detail.hasSave) {
    btnContinue.disabled = false;
    btnContinue.style.borderColor = "#00ff00";
    btnContinue.style.color = "#00ff00";
  }
});

// Set up embark listener once (not inside button click)
teamBuilder.addEventListener("embark", async (e) => {
  await gameStateManager.handleEmbark(e);
  // Squad will be updated from activeRunData in gamestate-changed handler
  // which has IDs after recruitment
});

btnNewRun.addEventListener("click", async () => {
  gameStateManager.startNewGame();
});

btnContinue.addEventListener("click", async () => {
  gameStateManager.continueGame();
});

// Handle request-team-builder event from HubScreen
window.addEventListener("request-team-builder", async (e) => {
  const { missionId } = e.detail;
  if (missionId) {
    // Set the active mission in MissionManager
    gameStateManager.missionManager.activeMissionId = missionId;
    // Transition to team builder
    await gameStateManager.transitionTo("STATE_TEAM_BUILDER", { missionId });
  }
});

// Handle save-and-quit event from HubScreen
window.addEventListener("save-and-quit", async () => {
  // Save current state and return to main menu
  // This could trigger a save dialog or auto-save
  console.log("Save and quit requested");
  // For now, just transition back to main menu
  // In the future, this could save and close the game
});

// Boot
gameStateManager.init();

// Lazy-load debug commands - only load when first accessed
// Creates async wrappers for all methods that load the module on first call
if (typeof window !== "undefined") {
  let debugCommandsInstance = null;
  let debugCommandsLoading = null;

  // List of all debug command methods (for creating async wrappers)
  const debugCommandMethods = [
    "addXP",
    "setLevel",
    "addSkillPoints",
    "unlockSkill",
    "unlockAllSkills",
    "addItem",
    "addCurrency",
    "killEnemy",
    "healUnit",
    "triggerVictory",
    "completeObjective",
    "triggerNarrative",
    "help",
    "listIds",
    "listPlayerIds",
    "listEnemyIds",
    "listItemIds",
    "listUnits",
    "listItems",
    "getState",
  ];

  // Create async wrapper functions for each method
  const createAsyncWrapper = (methodName) => {
    return function (...args) {
      // If already loaded, call directly
      if (debugCommandsInstance) {
        const method = debugCommandsInstance[methodName];
        if (typeof method === "function") {
          return method.apply(debugCommandsInstance, args);
        }
        return method;
      }

      // If currently loading, wait for it
      if (debugCommandsLoading) {
        return debugCommandsLoading.then(() => {
          const method = debugCommandsInstance[methodName];
          if (typeof method === "function") {
            return method.apply(debugCommandsInstance, args);
          }
          return method;
        });
      }

      // Start loading the module
      debugCommandsLoading = import("./core/DebugCommands.js").then(
        (module) => {
          const { debugCommands } = module;
          if (!debugCommands._initialized) {
            debugCommands.init();
            debugCommands._initialized = true;
          }
          debugCommandsInstance = debugCommands;
          return debugCommands;
        }
      );

      // Wait for load, then call the method
      return debugCommandsLoading.then(() => {
        const method = debugCommandsInstance[methodName];
        if (typeof method === "function") {
          return method.apply(debugCommandsInstance, args);
        }
        return method;
      });
    };
  };

  // Create the debugCommands object with async wrappers
  window.debugCommands = {};
  debugCommandMethods.forEach((methodName) => {
    window.debugCommands[methodName] = createAsyncWrapper(methodName);
  });

  // Add a note about async nature
  Object.defineProperty(window.debugCommands, "_note", {
    value: "Debug commands are lazy-loaded. First call may take a moment.",
    enumerable: false,
  });
}
