import { world, system } from "@minecraft/server";

// Escala de poder de equipamiento, de menor a mayor
const EQUIP_SCALE = ["leather", "chainmail", "copper", "iron", "diamond", "netherite"];

// Equivalencias de materiales personalizados con materiales vanilla
const MATERIAL_EQUIVALENTS = {
  "dungeon:cobalt": "iron",
  "dungeon:silver": "iron",
  "dungeon:tungsten": "diamond",
  "dungeon:jade": "diamond",
  "dungeon:glimmerite": "diamond",
  "dungeon:ancient": "diamond",
  "dungeon:viritum": "diamond",
  "dungeon:titanium": "diamond"
};

// Equivalencias para armas personalizadas con su nivel aproximado
const CUSTOM_WEAPON_EQUIVALENTS = {
  "dungeon:ancient_copper_sword": "iron",
  "dungeon:obsidian_sword": "diamond",
  "dungeon:dungeonglimmerite_hammer": "diamond",
  "dungeonmoon_sword": "iron",
  "dungeonsuper_bone_sword": "iron",
  "dungeon:cursed_sickle": "diamond",
  "dungeon:ancient_battleaxe": "diamond"
};

// Materiales especiales que generan encantamientos según nivel
const ENCHANTED_MATERIALS = {
  "netherite": { level: 5 },
  "glimmerite": { level: 4 },
  "viritum": { level: 4 },
  "titanium": { level: 5 }
};

// Partes de armadura
const ARMOR_PARTS = ["helmet", "chestplate", "leggings", "boots"];

// Relación entre las partes y los slots de comando
const ARMOR_COMMAND_SLOTS = {
  helmet: "head",
  chestplate: "chest",
  leggings: "legs",
  boots: "feet"
};

// Probabilidad de equipamiento según dificultad
const EQUIP_PROBABILITIES = {
  easy: 0.4,
  normal: 0.42,
  hard: 0.5,
  expert: 0.65
};

// Tipos de armas y su peso en el score
const WEAPONS = [
  { type: "sword", weight: 0.9 },
  { type: "spear", weight: 0.9 },
  { type: "axe", weight: 0.8 },
  { type: "bow", weight: 0.4 },
  { type: "crossbow", weight: 0.3 },
  { type: "trident", weight: 0.8 }
];

function getMaterialEquivalents(material) {
  // Devuelve todos los equivalentes posibles para un material, incluido el mismo
  const equivalents = [material];
  for (const [custom, base] of Object.entries(MATERIAL_EQUIVALENTS)) {
    if (base === material) equivalents.push(custom);
  }
  return equivalents;
}

// Devuelve una lista de encantamientos para un arma según su tipo y nivel
function getEnchantList(slot, type, level) {
  const enchantments = [];
  if (type === "weapon") {
    enchantments.push({ id: "sharpness", lvl: level });
    enchantments.push({ id: "unbreaking", lvl: level });
    if (slot.includes("bow") || slot.includes("crossbow")) {
      enchantments.push({ id: "power", lvl: level });
    }
  }
  return enchantments;
}

// Evalúa el gear total de un jugador y lo clasifica en nivel promedio
export async function evaluatePlayerGear(player) {
  const gear = {
    helmet: 0,
    chestplate: 0,
    leggings: 0,
    boots: 0,
    weapon: 0,
    totalScore: 0
  };

  // Armadura: prioriza del mejor al peor material para cada parte
  for (const part of ARMOR_PARTS) {
    for (let i = EQUIP_SCALE.length - 1; i >= 0; i--) {
      const material = EQUIP_SCALE[i];
      const targets = getMaterialEquivalents(material);
      let found = false;
      for (const m of targets) {
        try {
          const res = await player.runCommand(`testfor @s[hasitem={item=${m}_${part}}]`);
          if (res.successCount > 0) {
            gear[part] = i;
            found = true;
            break;
          }
        } catch { }
      }
      if (found) break; // No buscar materiales peores si ya tiene uno mejor
    }
  }

  // Armas personalizadas primero (por si tienen una de esas)
  for (const [customWeaponId, equivalentMat] of Object.entries(CUSTOM_WEAPON_EQUIVALENTS)) {
    try {
      const res = await player.runCommand(`testfor @s[hasitem={item=${customWeaponId}}]`);
      if (res.successCount > 0) {
        const i = EQUIP_SCALE.indexOf(equivalentMat);
        if (i !== -1 && i > gear.weapon) gear.weapon = i;
      }
    } catch { }
  }

  // Armas vanilla, priorizando mejor material (del mejor al peor)
  for (const weapon of WEAPONS) {
    for (let i = EQUIP_SCALE.length - 1; i >= 0; i--) {
      const material = EQUIP_SCALE[i];
      if ((material === "leather" || material === "chainmail") && (weapon.type === "sword" || weapon.type === "axe" || weapon.type === "spear")) continue;
      const targets = getMaterialEquivalents(material);
      let found = false;
      for (const m of targets) {
        const id = (["bow", "crossbow", "trident"].includes(weapon.type))
          ? weapon.type
          : `${m}_${weapon.type}`;
        try {
          const res = await player.runCommand(`testfor @s[hasitem={item=${id}}]`);
          if (res.successCount > 0) {
            const weighted = i * weapon.weight;
            if (weighted > gear.weapon) gear.weapon = weighted;
            found = true;
            break;
          }
        } catch { }
      }
      if (found) break;
    }
  }

  // Cálculo final del puntaje
  const sum = gear.helmet + gear.chestplate + gear.leggings + gear.boots + gear.weapon;
  gear.totalScore = +(sum / 5).toFixed(2);
  return gear;
}

const DIFF_MAX_INDEX = {
  easy: EQUIP_SCALE.indexOf("diamond"),     // hasta diamond
  normal: EQUIP_SCALE.indexOf("netherite"), // hasta netherite
  hard: EQUIP_SCALE.indexOf("netherite"),
  expert: EQUIP_SCALE.indexOf("netherite")
};


function clampInt(n, min, max) {
  return Math.max(min, Math.min(max, n | 0));
}

function matByIndex(i) {
  const idx = clampInt(Math.round(i), 0, EQUIP_SCALE.length - 1);
  return EQUIP_SCALE[idx];
}

// Probabilidad de mantener exactamente el mismo material que el jugador
const KEEP_SAME_CHANCE = {
  easy: 0.25,
  normal: 0.45,
  hard: 0.70,
  expert: 0.90
};

// Si no se mantiene igual, cuánto puede bajar (en niveles de EQUIP_SCALE)
const DOWNGRADE_MAX_STEPS = {
  easy: 3,     // puede bajar hasta 3 tiers
  normal: 2,
  hard: 1,
  expert: 1
};

function rollIndexWithDowngrade(playerIndex, difficulty) {
  const diffMax = DIFF_MAX_INDEX[difficulty] ?? (EQUIP_SCALE.length - 1);
  const maxAllowed = Math.min(diffMax, playerIndex); // nunca mejor que jugador ni que dificultad

  // Mantener igual
  if (Math.random() < (KEEP_SAME_CHANCE[difficulty] ?? 0.5)) {
    return maxAllowed;
  }

  // Downgrade controlado
  const maxSteps = DOWNGRADE_MAX_STEPS[difficulty] ?? 1;

  // Escoge cuánto bajar: 1..maxSteps (sesgo a bajar poco)
  let steps = 1;
  for (let i = 1; i <= maxSteps; i++) {
    // mientras más grande el i, menos probable
    if (Math.random() < 0.55) { steps = i; break; }
  }

  return clampInt(maxAllowed - steps, 0, maxAllowed);
}

export function equipMobWithGearDetails(mob, gear, difficulty = getCurrentDifficulty()) {
  const typeId = mob.typeId;
  // Clasificación de mobs
  const fullEquipmentMobs = [
    "dungeon:skeleton", "dungeon:beach_skeleton", "dungeon:dungeonzombie",
    "dungeon:lush_skeleton", "dungeon:miner_skeleton",
    "dungeon:purple_mummy", "dungeon:gray_mummy",
    "dungeon:frozen_stray", "dungeon:scorched_stray"
  ];
  const axeOnlyMobs = ["dungeon:gray_mummy"];
  const isArmorOnly = ["dungeon:miner_skeleton"];

  const hasFullGear = fullEquipmentMobs.includes(typeId);
  const hasOnlyAxe = axeOnlyMobs.includes(typeId);
  const hasOnlyarmor = isArmorOnly.includes(typeId);

  const mat = index => EQUIP_SCALE[Math.max(0, Math.min(5, Math.round(index)))];
  const equipChance = Math.min(1, Math.max(0, EQUIP_PROBABILITIES[difficulty] ?? 0.3));


  try {
    if (hasOnlyAxe) {
      const axeMat = mat(gear.weapon);
      if (axeMat !== "leather" && axeMat !== "chainmail") {
        mob.runCommand(`replaceitem entity @s slot.weapon.mainhand 0 minecraft:${axeMat}_axe`);
      }
      return;
    }

    if (hasFullGear) {
      if (!hasOnlyarmor) {
        const weaponMat = mat(gear.weapon);
        let weapon = chooseWeaponForMob(typeId, weaponMat);

        if (!weapon.includes("leather") && !weapon.includes("chainmail")) {
          mob.runCommand(`replaceitem entity @s slot.weapon.mainhand 0 ${weapon}`);
          // Encantamientos si aplica
          const equivalentMat = CUSTOM_WEAPON_EQUIVALENTS[weapon] ?? weaponMat;
          if (ENCHANTED_MATERIALS[equivalentMat]) {
            const level = ENCHANTED_MATERIALS[equivalentMat].level + (difficulty === "expert" ? 1 : 0);
            const enchList = getEnchantList("weapon", "weapon", level);
            for (const ench of enchList) {
              mob.runCommand(`enchant @s ${ench.id} ${ench.lvl}`);
            }
          }
        }
      }

      for (const part of ARMOR_PARTS) {
        if (Math.random() > equipChance) continue;

        let playerIdx = gear[part];
        if (playerIdx < 0) continue; // jugador no tiene esa pieza -> mob no la equipa

        const rolledIdx = rollIndexWithDowngrade(playerIdx, difficulty);
        const material = matByIndex(rolledIdx);
        const cmdSlot = ARMOR_COMMAND_SLOTS[part];

        mob.runCommand(`replaceitem entity @s slot.armor.${cmdSlot} 0 minecraft:${material}_${part}`);
      }




    }
  } catch (e) {
  }
}

function chooseWeaponForMob(typeId, material) {
  // Arqueros
  if (
    typeId.includes("skeleton") ||
    ["dungeon:frozen_stray", "dungeon:scorched_stray"].includes(typeId)
  ) {
    return "minecraft:bow";
  }

  // Zombie especial
  if (typeId === "dungeon:dungeonzombie") {
    if (Math.random() < 0.25) return "dungeon:ancient_copper_sword";
  }

  // Pool de armas cuerpo a cuerpo
  const weapons = [
    `minecraft:${material}_sword`,
    `minecraft:${material}_axe`
  ];

  return weapons[Math.floor(Math.random() * weapons.length)];
}

// Scoreboard: dificultad
export function getCurrentDifficulty() {
  const obj = world.scoreboard.getObjective("otherworldly_difficulty");
  if (!obj) return "normal";
  const participants = world.scoreboard.getParticipants();
  const entry = participants.find(p => p.displayName === "difficulty");
  if (!entry) return "normal";
  const score = obj.getScore(entry);
  switch (score) {
    case 0: return "easy";
    case 1: return "normal";
    case 2: return "hard";
    case 3: return "expert";
    default: return "normal";
  }
}

export function getDifficultyMultiplier() {
  const table = { easy: 0.9, normal: 0.95, hard: 0.99, expert: 1.0 };
  return table[getCurrentDifficulty()] ?? 0.4;
}

// Gear cache
const gearCache = new Map();
const gearBase = {
  helmet: -1,
  chestplate: -1,
  leggings: -1,
  boots: -1,
  weapon: 0,
  totalScore: 0
};

system.runInterval(async () => {
  for (const player of world.getPlayers()) {
    try {
      const gear = await evaluatePlayerGear(player);
      gearCache.set(player.id, gear);
    } catch (e) {
    }
  }
}, 120);

export function getCachedGear(player) {
  return gearCache.get(player.id) ?? gearBase;
}
