
import { world, system } from "@minecraft/server";
import { ActionFormData } from "@minecraft/server-ui";
import { pokemonCanLearn } from "./pokemonCanLearn.js";
import { MovesData } from "./moves.js";

// Simple in-memory battle manager (turn-based PvP)
const battles = new Map(); // battleId -> state

function _id() {
  return Math.random().toString(36).slice(2) + "-" + Date.now().toString(36);
}

function entityValid(ent) {
  try {
    if (!ent) return false;
    if (typeof ent.isValid === "function") return ent.isValid();
    void ent.id;
    return true;
  } catch (e) { return false; }
}

function playerById(id) {
  return world.getAllPlayers().find(p => p.id === id) || null;
}

function getMoveNames(poke) {
  try {
    const pokemonId = String(poke.typeId || "").replace("pr:", "");
    const moveList = pokemonCanLearn.get(pokemonId);

    const ids = [
      poke.getDynamicProperty("pr:move1"),
      poke.getDynamicProperty("pr:move2"),
      poke.getDynamicProperty("pr:move3"),
      poke.getDynamicProperty("pr:move4"),
    ];

    const names = ids.map((id) => {
      if (!id) return "";
      if (moveList && moveList.includes(id)) {
        const move = MovesData.find((m) => m.id === id);
        if (move && move.name) return String(move.name);
      }
      // fallback: show id if not in list
      return String(id);
    });

    // Ensure 4 buttons exist
    while (names.length < 4) names.push("");
    return names.slice(0, 4);
  } catch (e) {
    return ["", "", "", ""];
  }
}

function getLevel(poke) {
  const lvl = Number(poke?.getDynamicProperty?.("pr:level") ?? 1);
  return Number.isFinite(lvl) && lvl > 0 ? lvl : 1;
}

function setHealth(poke, newValue) {
  try {
    const hc = poke.getComponent("minecraft:health");
    if (!hc) return;
    hc.setCurrentValue(newValue);
    // force visual update
    try { poke.runCommandAsync?.("damage @s 0"); } catch (_) {}
  } catch (_) {}
}

function getHealth(poke) {
  try {
    const hc = poke.getComponent("minecraft:health");
    if (!hc) return 1;
    return Number(hc.currentValue ?? 1);
  } catch (_) { return 1; }
}

function calcDamage(attacker, defender) {
  const aLvl = getLevel(attacker);
  const dLvl = getLevel(defender);

  // Lightweight, consistent damage curve
  const base = 8;
  const levelDiff = aLvl - dLvl;
  let levelMul = 1 + (levelDiff * 0.08);
  levelMul = Math.max(0.6, Math.min(1.6, levelMul));

  const variance = 0.85 + (Math.random() * 0.3); // 0.85 - 1.15
  const dmg = Math.round(base * levelMul * variance);

  return Math.max(1, dmg);
}

function endBattle(state, winnerPlayerId, loserPlayerId) {
  const p1 = playerById(state.p1Id);
  const p2 = playerById(state.p2Id);

  state.active = false;
  battles.delete(state.battleId);

  // Clear flags
  try { state.p1Poke?.setDynamicProperty?.("pr:on_battle", false); } catch (_) {}
  try { state.p2Poke?.setDynamicProperty?.("pr:on_battle", false); } catch (_) {}
  try { p1?.setDynamicProperty?.("pr:on_battle", false); } catch (_) {}
  try { p2?.setDynamicProperty?.("pr:on_battle", false); } catch (_) {}

  // Notify
  const winner = playerById(winnerPlayerId);
  const loser = playerById(loserPlayerId);
  try { winner?.onScreenDisplay?.setActionBar?.(`§aYou won the PvP battle!`); } catch (_) {}
  try { loser?.onScreenDisplay?.setActionBar?.(`§cYou lost the PvP battle.`); } catch (_) {}
}


function scheduleFormRetry(state, fnName, delayTicks, maxTries, message) {
  if (!state.active) return;
  if (state[fnName] == null) state[fnName] = 0;
  state[fnName] = (state[fnName] || 0) + 1;
  if (state[fnName] > maxTries) {
    const p = playerById(state.turnPlayerId);
    try { p?.onScreenDisplay?.setActionBar?.(message || "§cCould not open battle UI. Close other menus and try again."); } catch (_) {}
    // Stop spamming; keep battle active but do not loop forever
    state[fnName] = 0;
    return;
  }
  system.runTimeout(() => {
    if (state.active) {
      // reset counter if successful is handled by caller
      try { /* noop */ } catch(_) {}
      // caller will call again
    }
  }, delayTicks);
}

function showTurnMenu(state) {
  if (!state.active) return;
  // Prevent overlapping UI calls (can freeze clients)
  if (state.uiLock) return;

  const currentPlayerId = state.turnPlayerId;
  const currentPlayer = playerById(currentPlayerId);
  const otherPlayerId = currentPlayerId === state.p1Id ? state.p2Id : state.p1Id;
  const otherPlayer = playerById(otherPlayerId);

  const attackerPoke = currentPlayerId === state.p1Id ? state.p1Poke : state.p2Poke;
  const defenderPoke = currentPlayerId === state.p1Id ? state.p2Poke : state.p1Poke;

  if (!currentPlayer || !otherPlayer || !entityValid(attackerPoke) || !entityValid(defenderPoke)) {
    // If someone disconnects or pokemon despawns, end battle gracefully
    state.active = false;
    battles.delete(state.battleId);
    try { currentPlayer?.onScreenDisplay?.setActionBar?.("§cBattle ended (missing player/pokemon)."); } catch (_) {}
    try { otherPlayer?.onScreenDisplay?.setActionBar?.("§cBattle ended (missing player/pokemon)."); } catch (_) {}
    return;
  }

  // Inform the other player it's not their turn
  try { otherPlayer.onScreenDisplay.setActionBar("§7Opponent is choosing..."); } catch (_) {}

  const attackerName = attackerPoke.nameTag || attackerPoke.typeId;
  const defenderName = defenderPoke.nameTag || defenderPoke.typeId;

  const form = new ActionFormData();
  form.title("PvP Battle");
  form.body(`§eYour turn!\n\n§aYour Pokémon: §f${attackerName}\n§cEnemy Pokémon: §f${defenderName}\n\n§7Pick an action:`);

  form.button("Fight");
  form.button("Forfeit");

  // Show on next tick to avoid restricted execution
  system.run(() => {
    state.uiLock = true;
    form.show(currentPlayer).then((res) => {
      state.uiRetry = 0;
      if (!state.active) return;
      if (res.canceled) {
        // If player closes the menu, don't spam-reopen (can freeze clients).
        state.needsManualOpen = true;
        try { currentPlayer.onScreenDisplay.setActionBar("§eBattle paused. Type §a!battle §eto reopen your turn."); } catch (_) {}
        return;
      }

      if (res.selection === 1) {
        // Forfeit
        endBattle(state, otherPlayerId, currentPlayerId);
        return;
      }

      // Fight → move selection
      showMoveMenu(state, currentPlayer, attackerPoke, defenderPoke);
    }).catch(() => {
      // If UI failed, pause and require manual reopen.
      if (!state.active) return;
      state.needsManualOpen = true;
      try { currentPlayer?.onScreenDisplay?.setActionBar?.("§eBattle paused. Type §a!battle §eto reopen your turn."); } catch (_) {}
      return;
        return;
      }

      // Back
      if (res.selection === displayed.length) {
        system.run(() => showTurnMenu(state));
        return;
      }

      // Apply attack
      const dmg = calcDamage(attackerPoke, defenderPoke);
      const defenderHp = getHealth(defenderPoke);
      const newHp = Math.round(Math.max(1, defenderHp - dmg));
      setHealth(defenderPoke, newHp);

      try { currentPlayer.onScreenDisplay.setActionBar(`§aYou used a move! §7(-${dmg} HP)`); } catch (_) {}

      // Check win
      if (newHp <= 1) {
        const winnerId = currentPlayer.id;
        const loserId = (winnerId === state.p1Id) ? state.p2Id : state.p1Id;
        endBattle(state, winnerId, loserId);
        return;
      }

      // Next player's turn
      state.turnPlayerId = (currentPlayer.id === state.p1Id) ? state.p2Id : state.p1Id;
      system.run(() => showTurnMenu(state));
    }).catch(() => {
      if (!state.active) return;
      scheduleFormRetry(state, "uiRetryMove", 20, 10, "§eClose other menus to choose a move…");
      system.runTimeout(() => { if (state.active) showTurnMenu(state); }, 20);
    });
  });
}

export function startTurnBasedPvpBattle(challenger, defender, challengerPokemon, defenderPokemon) {
  if (!challenger || !defender || !challengerPokemon || !defenderPokemon) return;

  // Basic validity
  if (!entityValid(challengerPokemon) || !entityValid(defenderPokemon)) return;

  // Create state
  const battleId = _id();
  const state = {
    battleId,
    active: true,
    p1Id: challenger.id,
    p2Id: defender.id,
    p1Poke: challengerPokemon,
    p2Poke: defenderPokemon,
    turnPlayerId: challenger.id, // challenger starts (can be changed later to use Speed)
    uiRetry: 0,
    uiRetryMove: 0,
  };

  battles.set(battleId, state);

  // Set flags
  try { challengerPokemon.setDynamicProperty("pr:on_battle", true); } catch (_) {}
  try { defenderPokemon.setDynamicProperty("pr:on_battle", true); } catch (_) {}
  try { challenger.setDynamicProperty("pr:on_battle", true); } catch (_) {}
  try { defender.setDynamicProperty("pr:on_battle", true); } catch (_) {}

  try { challenger.onScreenDisplay.setActionBar("§aPvP Battle started! Your turn."); } catch (_) {}
  try { defender.onScreenDisplay.setActionBar("§ePvP Battle started! Opponent goes first."); } catch (_) {}

  system.run(() => showTurnMenu(state));
}


export function reopenPvpTurnMenu(player) {
  try {
    if (!player) return;
    for (const state of battles.values()) {
      if (!state?.active) continue;
      if (state.p1Id !== player.id && state.p2Id !== player.id) continue;
      if (state.turnPlayerId !== player.id) {
        try { player.onScreenDisplay.setActionBar("§7It's not your turn."); } catch (_) {}
        return;
      }
      state.needsManualOpen = false;
      state.uiRetry = 0;
      showTurnMenu(state);
      return;
    }
    try { player.onScreenDisplay.setActionBar("§7You're not in a PvP battle."); } catch (_) {}
  } catch (_) {}
}
