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

const BLOCK_ID = "dungeon:tomb";
const SCOREBOARD = "tombstest";

const RANGE = 5.75;
const RANGE_INT = Math.ceil(RANGE);

const MAX_Y = 319;
const MIN_Y = -60;
const REQUIRED_COUNT = 3;

const CELL_SIZE = 8;

const RECHECK_TICKS = 40;

const CLEANUP_EVERY_TICKS = 200;

let TICK = 0;

const playerState = new Map(); 

const cellCache = new Map(); 

system.runInterval(() => {
  TICK++;
  if (TICK % CLEANUP_EVERY_TICKS === 0) cleanup();
}, 1);

function pid(player) {
  return player.id ?? player.name;
}

function cellKeyOf(loc) {
  const cx = Math.floor(loc.x / CELL_SIZE);
  const cy = Math.floor(loc.y / CELL_SIZE);
  const cz = Math.floor(loc.z / CELL_SIZE);
  return `${cx},${cy},${cz}`;
}

function cellId(player) {
  return `${player.dimension.id}|${cellKeyOf(player.location)}`;
}

function cleanup() {
  let players = [];
  try { players = world.getPlayers(); } catch { players = []; }

  const alive = new Set(players.map(p => pid(p)));

  for (const k of playerState.keys()) {
    if (!alive.has(k)) playerState.delete(k);
  }

  const minTick = TICK - (RECHECK_TICKS * 6);
  for (const [k, v] of cellCache.entries()) {
    if (v.tick < minTick) cellCache.delete(k);
  }
}

function cmd(player, s) {
  try { player.runCommand(s); } catch {}
}

function setActive(player, active) {
  if (active) {
    cmd(player, `fog @s push "dungeon:cemetery_fog" cemetery`);
    cmd(player, `tag @s add cursedcementery`);
  } else {
    cmd(player, `tag @s remove cursedcementery`);
    cmd(player, `fog @s remove cemetery`);
    cmd(player, `scoreboard players set @s ${SCOREBOARD} 0`);
  }
}

function setScore(player, v) {
  cmd(player, `scoreboard players set @s ${SCOREBOARD} ${v}`);
}

function scanTombsAround(player) {
  const loc = player.location;
  const dim = player.dimension;

  const px = Math.floor(loc.x);
  const py = Math.floor(loc.y);
  const pz = Math.floor(loc.z);

  const startX = px - RANGE_INT;
  const endX = px + RANGE_INT;
  const startZ = pz - RANGE_INT;
  const endZ = pz + RANGE_INT;

  const startY = Math.max(py - 3, MIN_Y);
  const endY = Math.min(py + 1, MAX_Y);

  let count = 0;

  for (let y = startY; y <= endY; y++) {
    for (let x = startX; x <= endX; x++) {
      for (let z = startZ; z <= endZ; z++) {
        const b = dim.getBlock({ x, y, z });
        if (b?.typeId === BLOCK_ID) {
          count++;
          if (count >= REQUIRED_COUNT) return count; // corte temprano
        }
      }
    }
  }

  return count;
}
function getCellCount(player, cell) {
  const cached = cellCache.get(cell);
  if (cached && (TICK - cached.tick) < RECHECK_TICKS) return cached.count;

  const count = scanTombsAround(player);
  cellCache.set(cell, { tick: TICK, count });
  return count;
}

export function detectBlocks(player) {
  const id = pid(player);

  let st = playerState.get(id);
  if (!st) {
    st = { active: false, lastScore: 0, lastCellKey: "", nextTick: 0 };
    playerState.set(id, st);
  }

  // throttle por jugador (aparte del cache por celda)
  if (TICK < st.nextTick) return;
  st.nextTick = TICK + 10; 

  const cKey = cellKeyOf(player.location);
  st.lastCellKey = cKey;

  const cell = cellId(player);
  const count = getCellCount(player, cell);
  const shouldBeActive = count >= REQUIRED_COUNT;

  // Solo comandos cuando cambie estado
  if (shouldBeActive !== st.active) {
    st.active = shouldBeActive;
    setActive(player, shouldBeActive);
  }

  // Solo scoreboard cuando cambie
  const score = shouldBeActive ? count : 0;
  if (score !== st.lastScore) {
    st.lastScore = score;
    setScore(player, score);
  }
}
