import { world, system, Player, BlockTypes, BlockPermutation } from "@minecraft/server";
import { buildToolMenu, decrementStack } from "./exchanger";
import { playerData } from "./exchanger";
import { cooldownMap } from "./block_randomizer";
import { placeConnected } from "./connected/pillars.js";
import { ConnectedBlockManager } from "./connected/pipes.js";
import { variantTool, editorModeReplaceTexture, paintTool, copyTool, rotateTool, setBlock, getBlockTextures } from "./main";
import { guiTextureSelect } from "./gui/index";
const eventQueue = [];
const CLICK_COOLDOWN = 200;
const toolSet = /* @__PURE__ */ new Set([
  "maca_probuilder:rotate",
  "maca_probuilder:copy",
  "maca_probuilder:painter",
  "maca_probuilder:variant",
  "maca_probuilder:editor_on",
  "maca_probuilder:editor_off"
]);
const logTypes = /* @__PURE__ */ new Set([
  "minecraft:oak_log",
  "minecraft:spruce_log",
  "minecraft:acacia_log",
  "minecraft:jungle_log",
  "minecraft:mangrove_log",
  "minecraft:warped_stem",
  "minecraft:birch_log",
  "minecraft:crimson_stem",
  "minecraft:dark_oak_log",
  "minecraft:pale_oak_log",
  "minecraft:cherry_log"
]);
const newToolSet = /* @__PURE__ */ new Set([
  "maca_probuilder:exchange",
  "maca_probuilder:randomizer",
  "maca_probuilder:claw_on",
  "maca_probuilder:claw_off"
]);
world.beforeEvents.itemUse.subscribe((event) => {
  const player = event.source;
  if (!(player instanceof Player))
    return;
  const item = event.itemStack;
  if (item == void 0)
    return;
  if (player.isSneaking && (item.typeId === "maca_probuilder:claw_off" || item.typeId === "maca_probuilder:claw_on" || item.typeId === "maca_probuilder:randomizer")) {
    event.cancel = true;
    system.run(() => {
      if (player.hasTag("maca_pb:claw_active")) {
        player.removeTag("maca_pb:claw_active");
      }
      buildToolMenu(player);
    });
    return;
  }
  if (!player.hasTag("maca_pb:claw_active"))
    return;
  if ((newToolSet.has(item.typeId) || toolSet.has(item.typeId)) && player.isSneaking)
    return;
  if (!cooldownMap.has(player.id)) {
    cooldownMap.set(player.id, { lastClickTime: Date.now() - 50 });
  }
  const currentTime = Date.now();
  const cooldownData = cooldownMap.get(player.id);
  const data = playerData.get(player.id);
  if (currentTime - cooldownData.lastClickTime > CLICK_COOLDOWN) {
    cooldownData.lastClickTime = currentTime;
    system.run(() => {
      const raycast = player.getBlockFromViewDirection({ maxDistance: 32 });
      if (!raycast || !raycast.block)
        return;
      const block = raycast.block;
      const distance = Math.sqrt(
        Math.pow(player.location.x - block.location.x, 2) + Math.pow(player.location.y - block.location.y, 2) + Math.pow(player.location.z - block.location.z, 2)
      );
      if (distance <= 5)
        return;
      if (block.typeId.includes("door") && !block.typeId.includes("iron") && !player.isSneaking) {
        if (item.typeId === "maca_probuilder:randomizer" && data.randomSwap)
          return;
        const states = block.permutation.getState("open_bit");
        const newState = states ? false : true;
        block.setPermutation(block.permutation.withState("open_bit", newState));
        return;
      }
      if (item != void 0 && BlockTypes.get(item.typeId) && !item.typeId.includes("shulker") && !player.hasTag("maca_probuilder:editormode")) {
        eventQueue.push({
          player,
          itemStack: item,
          swap: data.clawSwap
        });
      } else {
        const inventory = player.getComponent("inventory");
        if (item.hasTag("minecraft:is_axe") && logTypes.has(block.typeId)) {
          stripLog(player, block, item, inventory, player.selectedSlotIndex);
          return;
        }
        if (item.hasTag("minecraft:is_hoe") && (block.typeId === "minecraft:dirt" || block.typeId === "minecraft:grass_block" || block.typeId === "minecraft:podzol")) {
          tillLand(player, block, item, inventory, player.selectedSlotIndex);
          return;
        }
        if (item.hasTag("minecraft:is_shovel") && (block.typeId === "minecraft:dirt" || block.typeId === "minecraft:grass_block" || block.typeId === "minecraft:podzol" || block.typeId === "minecraft:mycelium")) {
          pathConvert(player, block, item, inventory, player.selectedSlotIndex);
          return;
        }
        if (item.typeId.includes("maca_probuilder:rotate")) {
          return rotateTool(block, player, item);
        }
        if (!block?.typeId.includes("maca_probuilder:"))
          return;
        if (player.hasTag("maca_probuilder:editormode")) {
          return editorModeReplaceTexture(block, player, item);
        }
        if (item.typeId.includes("maca_probuilder:painter")) {
          return paintTool(block, player, item);
        }
        if (item.typeId.includes("maca_probuilder:copy")) {
          return copyTool(block, player, item);
        }
        if (item.typeId.includes("maca_probuilder:variant")) {
          if (block?.hasTag("maca_probuilder:is_connected_vertical")) {
            return system.run(() => {
              placeConnected(player.dimension, block, true);
            });
          }
          if (block?.hasTag("maca_probuilder:is_connected_pipe")) {
            const manager = new ConnectedBlockManager(block, block?.typeId, "placed", true);
            return system.run(() => {
              manager.updateBlock();
            });
          }
          return variantTool(block, player, item);
        }
        if (toolSet.has(item.typeId)) {
          player.setDynamicProperty("maca_probuilder:stored_lore", item.getLore()[0]);
          return;
        }
      }
    });
  }
});
world.beforeEvents.itemUseOn.subscribe((event) => {
  const player = event.source;
  if (!(player instanceof Player))
    return;
  const item = event.itemStack;
  if (item == void 0)
    return;
  const data = playerData.get(player.id);
  if (player.hasTag("maca_pb:claw_active") && BlockTypes.get(item.typeId) && !item.typeId.includes("shulker")) {
    event.cancel = true;
    if (!cooldownMap.has(player.id)) {
      cooldownMap.set(player.id, { lastClickTime: Date.now() - CLICK_COOLDOWN });
    }
    const currentTime = Date.now();
    const cooldownData = cooldownMap.get(player.id);
    if (currentTime - cooldownData.lastClickTime > CLICK_COOLDOWN) {
      cooldownData.lastClickTime = currentTime;
      system.run(() => {
        if (item != void 0 && BlockTypes.get(item.typeId) && !item.typeId.includes("shulker")) {
          eventQueue.push({
            player,
            itemStack: item,
            swap: data.clawSwap
          });
        }
      });
    }
    return;
  }
});
function pathConvert(player, block, item, inventory, selectedSlotIndex) {
  if (block.above().typeId === "minecraft:air") {
    applyDurabilityDamage(
      player,
      item,
      inventory,
      selectedSlotIndex
    );
    block.setType("minecraft:grass_path");
    player.dimension.playSound("use.grass", block.location);
  }
}
function tillLand(player, block, item, inventory, selectedSlotIndex) {
  if (block.above().typeId === "minecraft:air") {
    applyDurabilityDamage(
      player,
      item,
      inventory,
      selectedSlotIndex
    );
    block.setType("minecraft:farmland");
    player.dimension.playSound("use.grass", block.location);
  }
}
function stripLog(player, block, selectedItem, inventory, selectedSlotIndex) {
  const stippedLogType = `minecraft:stripped_${block.typeId.split(":")[1]}`;
  if (!stippedLogType)
    return;
  const currentPermutation = block.permutation;
  const blockStates = currentPermutation.getAllStates();
  const customBlockFace = blockStates["pillar_axis"];
  const strippedLogPermutation = BlockPermutation.resolve(
    stippedLogType
  ).withState("pillar_axis", customBlockFace);
  block.setPermutation(strippedLogPermutation);
  player.playSound("item.axe.strip");
  applyDurabilityDamage(player, selectedItem, inventory, selectedSlotIndex);
}
function applyDurabilityDamage(player, item, inventory, slotIndex) {
  if (player.getGameMode() === "creative")
    return;
  const durabilityComponent = item.getComponent("minecraft:durability");
  if (durabilityComponent) {
    const { unbreakingLevel } = getRelevantEnchantments(item);
    if (Math.random() < 1 / (unbreakingLevel + 1)) {
      const newDamage = durabilityComponent.damage + 1;
      if (newDamage >= durabilityComponent.maxDurability) {
        inventory.container.setItem(slotIndex, void 0);
        player.playSound("random.break");
      } else {
        durabilityComponent.damage = newDamage;
        inventory.container.setItem(slotIndex, item);
      }
    }
  }
}
function getRelevantEnchantments(item) {
  let unbreakingLevel = 0;
  let hasSilkTouch = false;
  try {
    const enchantableComponent = item.getComponent("minecraft:enchantable");
    if (enchantableComponent) {
      const enchantments = enchantableComponent.getEnchantments();
      for (const enchant of enchantments) {
        if (enchant.type.id === "unbreaking") {
          unbreakingLevel = enchant.level;
        } else if (enchant.type.id === "silk_touch") {
          hasSilkTouch = true;
        }
      }
    }
  } catch (error) {
  }
  return { unbreakingLevel, hasSilkTouch };
}
function processQueue() {
  const eventsToProcess = eventQueue.splice(0, eventQueue.length);
  for (const event of eventsToProcess) {
    placeBlock(event.player, event.itemStack, event.swap);
  }
  system.runTimeout(processQueue, 2);
}
processQueue();
function placeBlock(player, itemStack, swap) {
  const raycast = player.getBlockFromViewDirection({ maxDistance: 32 });
  if (!raycast || !raycast.block)
    return;
  const face = raycast.face;
  let relativeBlock = raycast.block;
  let newBlock = void 0;
  if (!swap) {
    switch (face.toLowerCase()) {
      case "up":
        relativeBlock = raycast.block.above();
        break;
      case "down":
        relativeBlock = raycast.block.below();
        break;
      case "east":
        relativeBlock = raycast.block.east();
        break;
      case "west":
        relativeBlock = raycast.block.west();
        break;
      case "north":
        relativeBlock = raycast.block.north();
        break;
      case "south":
        relativeBlock = raycast.block.south();
        break;
    }
    if (relativeBlock?.typeId !== "minecraft:air")
      return;
  }
  decrementStack(player, player.selectedSlotIndex, swap ? relativeBlock?.typeId : false);
  player.dimension.playSound("maca_probuilder.tool.paste", relativeBlock.location);
  newBlock = itemStack.typeId.includes("minecraft:") ? itemStack.typeId.split(":")[1] : itemStack.typeId;
  if (itemStack?.typeId === "minecraft:lever") {
    const leverDirection = getLeverDirection(face, player);
    player.runCommand(`setblock ${relativeBlock.location.x} ${relativeBlock.location.y} ${relativeBlock.location.z} ${newBlock} ["lever_direction"="${leverDirection}"]`);
  } else if (itemStack?.typeId.includes("_button")) {
    const buttonDirection = getButtonDirection(face);
    player.runCommand(`setblock ${relativeBlock.location.x} ${relativeBlock.location.y} ${relativeBlock.location.z} ${newBlock} ["facing_direction"=${buttonDirection}]`);
  } else {
    player.runCommand(`setblock ${relativeBlock.location.x} ${relativeBlock.location.y} ${relativeBlock.location.z} ${newBlock}`);
    const block = player.dimension.getBlock(relativeBlock.location);
    const blockPerms = block.permutation.getAllStates();
    try {
      if (blockPerms != void 0) {
        setPerms(blockPerms, player, block, face, raycast.faceLocation);
      }
    } catch (e) {
    }
  }
  if (newBlock.includes("maca_probuilder:")) {
    if (itemStack && itemStack != void 0) {
      var storedLore = itemStack.getLore()[0];
    } else {
      storedLore = player.getDynamicProperty("maca_probuilder:stored_lore");
    }
    const block = player.dimension.getBlock(relativeBlock.location);
    if (player.isSneaking) {
      const validTextures = getBlockTextures(block).map((x) => x.name);
      guiTextureSelect(player, block, validTextures, "", validTextures.findIndex((x) => x === storedLore));
    }
    if (storedLore != void 0)
      setBlock(player, block, storedLore, false);
  }
}
;
function getLeverDirection(face, player) {
  const playerRotation = player.getRotation();
  const yaw = (playerRotation.y + 360) % 360;
  switch (face) {
    case "Up":
      return yaw >= 315 || yaw < 45 || yaw >= 135 && yaw < 225 ? "up_north_south" : "up_east_west";
    case "Down":
      return yaw >= 315 || yaw < 45 || yaw >= 135 && yaw < 225 ? "down_north_south" : "down_east_west";
    case "North":
      return "north";
    case "South":
      return "south";
    case "East":
      return "east";
    default:
      return "west";
  }
}
function getButtonDirection(face) {
  switch (face) {
    case "Down":
      return 0;
    case "Up":
      return 1;
    case "North":
      return 2;
    case "South":
      return 3;
    case "West":
      return 4;
    case "East":
      return 5;
    default:
      return 1;
  }
}
function setPerms(blockPerms, player, block, face, faceLocation) {
  let finalPerms = [];
  for (const [perm, value] of Object.entries(blockPerms)) {
    let finalValue = value;
    try {
      switch (perm) {
        case "minecraft:cardinal_direction":
          if (block.typeId.includes("door") && !block.typeId.includes("trap")) {
            finalValue = doorCardState(player);
          } else {
            finalValue = cardDirectionState(player);
          }
          break;
        case "minecraft:vertical_half":
          finalValue = verticalHalfState(faceLocation, face);
          break;
        case "upside_down_bit":
          finalValue = upsideDownState(face, faceLocation);
          break;
        case "facing_direction":
          finalValue = facingState(face);
          break;
        case "direction":
          if (block.typeId.includes("door") && !block.typeId.includes("trap")) {
            finalValue = doorDirectionState(player);
          } else {
            finalValue = directionState(player);
          }
          break;
        case "weirdo_direction":
          finalValue = weirdoState(player);
          break;
        case "block_face":
          finalValue = face.toLowerCase();
          break;
        case "pillar_axis":
          finalValue = pillarState(face);
          break;
        default:
          break;
      }
      finalPerms.push({ perm, finalValue });
    } catch (e) {
    }
  }
  for (const [perm, value] of Object.entries(finalPerms)) {
    block.setPermutation(block.permutation.withState(value.perm, value.finalValue));
  }
}
function upsideDownState(face, faceLocation) {
  let stateValue;
  if (face === "Down") {
    stateValue = true;
  } else if (face === "Up") {
    stateValue = false;
  } else if (faceLocation.y < 0.5) {
    stateValue = false;
  } else {
    stateValue = true;
  }
  return stateValue;
}
function verticalHalfState(faceLocation, face) {
  let stateValue;
  if (face === "Down") {
    stateValue = "top";
  } else if (face === "Up") {
    stateValue = "bottom";
  } else if (faceLocation.y < 0.5) {
    stateValue = "bottom";
  } else {
    stateValue = "top";
  }
  return stateValue;
}
function facingState(face) {
  let stateValue;
  switch (face) {
    case "Down":
      stateValue = 0;
      break;
    case "Up":
      stateValue = 0;
      break;
    case "East":
      stateValue = 4;
      break;
    case "West":
      stateValue = 5;
      break;
    case "South":
      stateValue = 2;
      break;
    default:
      stateValue = 3;
      break;
  }
  return stateValue;
}
function directionState(player) {
  const rotation = player.getRotation();
  const rad = rotation.y * Math.PI / 180;
  const directionX = -Math.sin(rad);
  const directionZ = Math.cos(rad);
  let stateValue;
  if (Math.abs(directionX) > Math.abs(directionZ)) {
    stateValue = directionX > 0 ? 1 : 0;
  } else {
    stateValue = directionZ > 0 ? 3 : 2;
  }
  return stateValue;
}
function weirdoState(player) {
  const rotation = player.getRotation();
  const rad = rotation.y * Math.PI / 180;
  const directionX = -Math.sin(rad);
  const directionZ = Math.cos(rad);
  let stateValue;
  if (Math.abs(directionX) > Math.abs(directionZ)) {
    stateValue = directionX > 0 ? 0 : 1;
  } else {
    stateValue = directionZ > 0 ? 2 : 3;
  }
  return stateValue;
}
function pillarState(face) {
  let stateValue;
  if (["North", "South"].includes(face)) {
    stateValue = "z";
  } else if (["East", "West"].includes(face)) {
    stateValue = "x";
  } else {
    stateValue = "y";
  }
  return stateValue;
}
function cardDirectionState(player) {
  let stateValue;
  const rotation = player.getRotation();
  const rad = rotation.y * Math.PI / 180;
  const directionX = -Math.sin(rad);
  const directionZ = Math.cos(rad);
  if (Math.abs(directionX) > Math.abs(directionZ)) {
    stateValue = directionX > 0 ? "east" : "west";
  } else {
    stateValue = directionZ > 0 ? "south" : "north";
  }
  return stateValue;
}
function doorCardState(player) {
  let stateValue;
  const rotation = player.getRotation();
  const rad = rotation.y * Math.PI / 180;
  const directionX = -Math.sin(rad);
  const directionZ = Math.cos(rad);
  if (Math.abs(directionX) > Math.abs(directionZ)) {
    stateValue = directionX > 0 ? "south" : "north";
  } else {
    stateValue = directionZ > 0 ? "east" : "west";
  }
  return stateValue;
}
function doorDirectionState(player) {
  const rotation = player.getRotation();
  const rad = rotation.y * Math.PI / 180;
  const directionX = -Math.sin(rad);
  const directionZ = Math.cos(rad);
  let stateValue;
  if (Math.abs(directionX) > Math.abs(directionZ)) {
    stateValue = directionX > 0 ? 0 : 1;
  } else {
    stateValue = directionZ > 0 ? 2 : 3;
  }
  return stateValue;
}
export {
  getButtonDirection,
  getLeverDirection,
  setPerms
};
