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

import "./dungeonbadlucktest.js";
import "./dungeonitems.js";
import "./dungeonspider_boss.js";
import "./dungeonguide.js";
import "./dungeontools_blocks.js";
import { regeneration } from "./dungeonsaturation.js";
import "./dungeonblocks.js";
import "./dungeonSkeletons.js";
import "./dungeonlight.js";

import { toolseffects } from "./dungeoncombat.js";
import "./dungeonaimobs.js";
import { equipMobWithGearDetails, getDifficultyMultiplier, getCachedGear } from "./dungeonDifficulty.js";
import { detectBlocks } from "./dungeontomb.js";
import { executeDeathCommands, moonstone, controller_player } from "./dungeonplayer_functions.js";
import { isLookingAtHead } from "./dungeongorgona_function.js";
import { info, detectDungeonBlocks } from "./dungeonfunctions.js";
import { cave_event } from "./dungeoncave_event.js";
import { registerBlockComponents } from "./dungeoncore.js";
import { initialize } from "./dungeonalive.js";
import "./dungeonalive.js";
import { detectCloudBlocks } from "./dungeoncloudblock.js";
import "./fear_ui.js";

import { specialarmors } from "./armor_set_bonus.js";
import { cobalt_armor } from "./armors/cobalt.js";
import { tungsten_armor } from "./armors/tungsten.js";
import { jade_armor } from "./armors/jade.js";
import "./armors/glimmerite.js";
import "./armors/viritum.js";
import "./armors/ancient.js";
import "./dungeondifficulty_config.js";
import "./armors/armors_index.js";
import "./accessories/index.js";
import "./functionality/game.js";
import "./functionality/difficulty_aura.js";
import { registerSoilSpawn } from "./spawn/features/soilspawn.js";
import { fm_rise } from "./dungeonmoon_phase_test.js";

import { initBestiary } from "./bestiary/index.js";

specialarmors([cobalt_armor, tungsten_armor, jade_armor]);

const T = {
  UI: 40,
  INIT: 0,
  DEATH: 0,
  LOOK_HEAD: 2,
  INFO: 1,
  DETECT_BLOCKS: 60,
  REMOVE_VIEW_TAG: 60,
  REGEN: 10, //35=1.75s
};

const VALID_EQUIP_TYPES = new Set([
  "dungeon:dungeonzombie", "dungeon:beach_skeleton", "dungeon:lush_skeleton",
  "dungeon:miner_skeleton", "dungeon:gray_mummy", "dungeon:purple_mummy",
  "dungeon:skeleton", "dungeon:frozen_stray", "dungeon:scorched_stray"
]);

// Presupuestos por tick
const BATCH_CORE = 2;
const BATCH_HEAVY = 1;         // escaneos de bloques por tick (cloud/tomb)
const BATCH_CONTROLLER = 3;    // controller por tick (en vez de todos)

// Estado
let globalTick = 0;
let regenNextTick = 0;

let playersCache = [];
let pointerCore = 0;
let pointerHeavy = 0;
let pointerController = 0;

const perPlayer = new Map();    // id -> bag
const regenNext = new Map();    // id -> nextTick

world.afterEvents.entityHurt.subscribe(({ damageSource, hurtEntity }) => {
  const attacker = damageSource.damagingEntity;
  if (attacker?.typeId === "minecraft:player") {
    try { toolseffects(attacker, hurtEntity); } catch { }
  }
});

world.afterEvents.playerSpawn.subscribe(({ player }) => {
  try { player.runCommand(`give @s[tag=!guide_book] dungeon:vampiric_amulet 1 0 {"keep_on_death": {}}`); } catch { }
  try { player.runCommand(`give @s[tag=!guide_book] dungeon:guide_book 1 0 {"keep_on_death": {}}`); } catch { }
  try { player.runCommand(`tag @s[tag=!guide_book] add fear_info`); } catch { }
  try { player.runCommand(`tag @s[tag=!guide_book] add guide_book`); } catch { }
  try { player.removeTag("cursedcementery"); } catch { }
  try { player.removeTag("invulnerable"); } catch { }
  try { player.removeTag("cave_fog_active"); } catch { }
  try { player.runCommand("scoreboard players set @s tombstest 0"); } catch { }
  try { player.runCommand("fog @s remove cemetery"); } catch { }
  try { player.runCommand("fog @s remove dcave_fog"); } catch { }
});

world.afterEvents.entitySpawn.subscribe(({ entity }) => {
  try {
    if (!entity || entity.hasTag("__equipped")) return;
  } catch { return; }

  if (!VALID_EQUIP_TYPES.has(entity.typeId)) return;

  let players = [];
  try {
    players = entity.dimension.getPlayers({ location: entity.location, maxDistance: 96 });
  } catch {
    try { players = world.getPlayers(); } catch { return; }
  }

  if (!players || players.length === 0) return;

  let bestGear = null;
  let bestScore = -Infinity;

  let multiplier = 1;
  try { multiplier = getDifficultyMultiplier(); } catch { }

  for (const p of players) {
    try {
      const gear = getCachedGear(p);
      if (gear && gear.totalScore > bestScore) {
        bestGear = gear;
        bestScore = gear.totalScore;
      }
    } catch { }
  }

  if (!bestGear) return;

  try {
    equipMobWithGearDetails(entity, {
      helmet: bestGear.helmet * multiplier,
      chestplate: bestGear.chestplate * multiplier,
      leggings: bestGear.leggings * multiplier,
      boots: bestGear.boots * multiplier,
      weapon: bestGear.weapon * multiplier,
      totalScore: bestGear.totalScore * multiplier
    });
    entity.addTag("__equipped");
  } catch { }
});

// MAIN LOOP
system.runInterval(() => {
  let players = [];
  try { players = world.getPlayers(); } catch { players = []; }

  // refresca cache y limpia maps cada 20 ticks
  if (globalTick % 20 === 0) {
    playersCache = players;
    if (pointerCore >= playersCache.length) pointerCore = 0;
    if (pointerHeavy >= playersCache.length) pointerHeavy = 0;
    if (pointerController >= playersCache.length) pointerController = 0;

    const ids = new Set(playersCache.map(p => p.id));
    for (const key of perPlayer.keys()) if (!ids.has(key)) perPlayer.delete(key);
    for (const key of regenNext.keys()) if (!ids.has(key)) regenNext.delete(key);
  } else {
    playersCache = players;
  }

  if (playersCache.length === 0) {
    globalTick++;
    return;
  }

  // cave_event: 1 sola vez, NO por jugador
  try { cave_event(); } catch { }
  fm_rise();

  if (globalTick >= regenNextTick) {
    try {
      const players = playersCache; // o world.getPlayers()
      if (players.length > 0) regeneration(players[0]); // llamar 1 vez
    } catch { }
    regenNextTick = globalTick + T.REGEN;
  }


  // CORE batch (barato)
  for (let i = 0; i < BATCH_CORE && pointerCore < playersCache.length; i++, pointerCore++) {
    const p = playersCache[pointerCore];
    const id = p.id;

    let bag = perPlayer.get(id);
    if (!bag) bag = { init: 0, death: 0, info: 0, detect: 0, view: 0 };

    bag.init++;
    bag.death++;
    bag.info++;
    bag.detect++;
    bag.view++;

    initialize(p);

    if (bag.death >= T.DEATH) {
      try { executeDeathCommands(p); } catch { }
      bag.death = 0;
    }

    try { moonstone(p); } catch { }

    if (bag.info >= T.INFO) {
      try {
        if (p.hasTag("spectral_amulet") && !p.hasTag("luck_info")) {
          info(p);
          detectDungeonBlocks(p);
        }
      } catch { }
      bag.info = 0;
    }

    if (bag.view >= T.REMOVE_VIEW_TAG) {
      try { if (p.hasTag("luck_info")) p.removeTag("luck_info"); } catch { }
      bag.view = 0;
    }

    perPlayer.set(id, bag);
  }

  if (pointerCore >= playersCache.length) pointerCore = 0;

  // HEAVY batch (escaneos de bloques) separado y limitado
  for (let i = 0; i < BATCH_HEAVY && pointerHeavy < playersCache.length; i++, pointerHeavy++) {
    const p = playersCache[pointerHeavy];
    const id = p.id;

    let bag = perPlayer.get(id);
    if (!bag) bag = { init: 0, death: 0, info: 0, detect: 0, view: 0 };

    bag.detect++;

    if (bag.detect >= T.DETECT_BLOCKS) {
      try { detectCloudBlocks(p); } catch { }
      try { detectBlocks(p); } catch { }
      bag.detect = 0;
    }

    perPlayer.set(id, bag);
  }

  if (pointerHeavy >= playersCache.length) pointerHeavy = 0;

  // controller_player: round-robin, NO todos a la vez
  for (let i = 0; i < BATCH_CONTROLLER && pointerController < playersCache.length; i++, pointerController++) {
    const p = playersCache[pointerController];
    try { controller_player(p); } catch { }

    // mirar cabeza también aquí (round-robin)
    if (T.LOOK_HEAD > 0 && (globalTick % T.LOOK_HEAD === 0)) {
      try { isLookingAtHead(p); } catch { }
    }
  }

  if (pointerController >= playersCache.length) pointerController = 0;

  globalTick++;
}, 2);

system.beforeEvents.startup.subscribe(({ blockComponentRegistry }) => {
  try { registerBlockComponents(blockComponentRegistry); } catch { }
});

try { registerSoilSpawn(); } catch { }

 initBestiary();
