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

// ─── Constants ──────────────────────────────────────────────
const PRIVATE_BLOCK = "silverlabs:private_chest";
const VANILLA_CHEST = "minecraft:chest";
const PROP_KEY = "private_chests_v1";

// ─── State ──────────────────────────────────────────────────
// In-memory mirror of dynamic property: { "x,y,z,dim": { ownerId, ownerName } }
let chests = {};

function loadState() {
  try {
    const raw = world.getDynamicProperty(PROP_KEY);
    if (raw && typeof raw === "string") {
      chests = JSON.parse(raw);
    }
  } catch (e) {
    world.sendMessage(`§c[Private Chest] Failed to load state: ${e.message}`);
    chests = {};
  }
}

function saveState() {
  try {
    world.setDynamicProperty(PROP_KEY, JSON.stringify(chests));
  } catch (e) {
    world.sendMessage(`§c[Private Chest] Failed to save state: ${e.message}`);
  }
}

function keyOf(loc, dimensionId) {
  return `${Math.floor(loc.x)},${Math.floor(loc.y)},${Math.floor(loc.z)},${dimensionId}`;
}

function claim(loc, dimensionId, player) {
  chests[keyOf(loc, dimensionId)] = { ownerId: player.id, ownerName: player.name };
  saveState();
}

function release(loc, dimensionId) {
  delete chests[keyOf(loc, dimensionId)];
  saveState();
}

function getOwner(loc, dimensionId) {
  return chests[keyOf(loc, dimensionId)] || null;
}

// ─── Chest facing from player rotation ──────────────────────
// Bedrock yaw: 0=south, 90=west, 180=north, -90=east. Chest front faces the player.
function chestFacing(yaw) {
  let y = yaw;
  while (y > 180) y -= 360;
  while (y < -180) y += 360;
  if (y >= -45 && y < 45) return "north";   // player facing south
  if (y >= 45 && y < 135) return "east";    // player facing west
  if (y >= -135 && y < -45) return "west";  // player facing east
  return "south";                            // player facing north
}

// ─── Placement: swap custom block → vanilla chest + claim ──
world.afterEvents.playerPlaceBlock.subscribe((event) => {
  const block = event.block;
  if (block.typeId !== PRIVATE_BLOCK) return;

  const player = event.player;
  const loc = block.location;
  const dim = block.dimension;
  const facing = chestFacing(player.getRotation().y);

  try {
    dim.runCommand(
      `setblock ${loc.x} ${loc.y} ${loc.z} chest ["minecraft:cardinal_direction":"${facing}"]`
    );
  } catch (e) {
    // Older block-state syntax fallback (rare)
    try {
      dim.runCommand(`setblock ${loc.x} ${loc.y} ${loc.z} chest`);
    } catch (_) {}
  }

  claim(loc, dim.id, player);
  player.sendMessage(`§6[Private Chest] §7Locked to you. Only you can open or break it.`);
});

// ─── Interact: block opening for non-owners ─────────────────
try {
  world.beforeEvents.playerInteractWithBlock.subscribe((event) => {
    const block = event.block;
    if (block.typeId !== VANILLA_CHEST) return;
    const owner = getOwner(block.location, block.dimension.id);
    if (!owner) return;
    if (owner.ownerId === event.player.id) return;
    event.cancel = true;
    const playerRef = event.player;
    system.run(() =>
      playerRef.sendMessage(`§c[Private Chest] §7This chest belongs to §f${owner.ownerName}§7.`)
    );
  });
} catch (e) {
  console.warn(`[Private Chest] beforeEvents.playerInteractWithBlock unavailable: ${e}`);
}

// ─── Break: protect for non-owners; owner break drops the custom item back ──
try {
  world.beforeEvents.playerBreakBlock.subscribe((event) => {
    const block = event.block;
    if (block.typeId !== VANILLA_CHEST) return;
    const owner = getOwner(block.location, block.dimension.id);
    if (!owner) return;

    const player = event.player;

    if (owner.ownerId !== player.id) {
      event.cancel = true;
      system.run(() =>
        player.sendMessage(`§c[Private Chest] §7This chest belongs to §f${owner.ownerName}§7. You can't break it.`)
      );
      return;
    }

    // Owner breaking — cancel default drop, manually eject contents + return the custom item.
    event.cancel = true;
    const loc = { x: block.location.x, y: block.location.y, z: block.location.z };
    const dim = block.dimension;

    system.run(() => {
      try {
        const inv = dim.getBlock(loc)?.getComponent("inventory");
        const container = inv?.container;
        const dropPos = { x: loc.x + 0.5, y: loc.y + 0.5, z: loc.z + 0.5 };
        if (container) {
          for (let i = 0; i < container.size; i++) {
            const item = container.getItem(i);
            if (item) {
              dim.spawnItem(item, dropPos);
              container.setItem(i, undefined);
            }
          }
        }
        dim.spawnItem(new ItemStack(PRIVATE_BLOCK, 1), dropPos);
        dim.runCommand(`setblock ${loc.x} ${loc.y} ${loc.z} air`);
      } catch (e) {
        player.sendMessage(`§c[Private Chest] Error during break: ${e.message}`);
      }
      release(loc, dim.id);
    });
  });
} catch (e) {
  console.warn(`[Private Chest] beforeEvents.playerBreakBlock unavailable: ${e}`);
}

// ─── Boot ──────────────────────────────────────────────────
system.run(() => {
  loadState();
  world.sendMessage("§6[Private Chest] §7Owner-locked chest system loaded.");
});
