import { world, system, ItemStack, BlockPermutation } from "@minecraft/server";
import { randomTickComponent, OnTickComponent, leafDrop } from "./OnTick";
import { leafDefaultComponent } from "./tree";
import { FenceInteractComponent, PlaceComponent, PlaceGateComponent, GateInteract } from "./fence";
import { slabComponent } from "./slabs";
// import "door";
// import "trapdoor";
// import "fallingLeaves";

// Add more mappings here as needed - Note, the doors need to be set on door.js at line 237.
export const isSlab = new Set(["hb_hr:grim_stone_bricks_slab", "hb_hr:grim_stone_bricks_slab_item", "hb_hr:white_oak_slab", "hb_hr:blight_slab", "hb_hr:blight_slab_item", "hb_hr:black_slab", "hb_hr:black_slab_item", "hb_hr:cursed_slab", "hb_hr:cursed_slab_item", "hb_hr:white_oak_slab_item"]);
export const fenceSet = new Set(["hb_hr:white_oak_fence", "hb_hr:white_oak_fence_gate", "hb_hr:blight_fence", "hb_hr:blight_fence_gate", "hb_hr:black_fence", "hb_hr:black_fence_gate", "hb_hr:cursed_fence", "hb_hr:cursed_fence_gate", "hb_hr:blight_fence_inventory"]);

export const fenceMap = new Map([
  ["hb_hr:black_fence", "hb_hr:black_fence"],
  ["hb_hr:black_fence_inventory", "hb_hr:black_fence"],
  ["hb_hr:blight_fence", "hb_hr:blight_fence"],
  ["hb_hr:blight_fence_inventory", "hb_hr:blight_fence"],
  ["hb_hr:cursed_fence", "hb_hr:cursed_fence"],
  ["hb_hr:cursed_fence_inventory", "hb_hr:cursed_fence"],
  ["hb_hr:white_oak_fence_inventory", "hb_hr:white_oak_fence"],
  ["hb_hr:blight_fence_inventory_item", "hb_hr:blight_fence"],
  ["hb_hr:white_oak_fence_inventory_item", "hb_hr:white_oak_fence"],
  ["hb_hr:white_oak_fence", "hb_hr:white_oak_fence"],
]);
export const leafSet = new Set(["hb_hr:white_oak_leaves", "hb_hr:blight_leaves", "hb_hr:black_leaves"]);

export const fruitSet = new Set(["hb_hr:blight_leaves"]);
export const leafDropMap = new Map([
  ["hb_hr:black_leaves", "hb_hr:black_sapling"],
  ["hb_hr:blight_leaves", "hb_hr:blight_sapling"],
  ["hb_hr:cursed_leaves", "hb_hr:cursed_sapling"],
  ["hb_hr:white_oak_leaves", "hb_hr:custom_sapling_placer"],
]);
export const saplingBlocks = [
  {
    blockID: "hb_hr:white_oak_sapling",
    maxStage: 2,
    growChance: {
      numerator: 1,
      denominator: 3,
    },
  },
  {
    blockID: "hb_hr:blight_sapling",
    maxStage: 2,
    growChance: {
      numerator: 1,
      denominator: 3,
    },
  },
  {
    blockID: "hb_hr:blight_leaves",
    maxStage: 3,
    growChance: {
      numerator: 1,
      denominator: 7, // adjust this to adjust speed of fruit growth
    },
  },
  {
    blockID: "hb_hr:black_sapling",
    maxStage: 2,
    growChance: {
      numerator: 1,
      denominator: 3,
    },
  },
  {
    blockID: "hb_hr:black_leaves",
    maxStage: 3,
    growChance: {
      numerator: 1,
      denominator: 7, // adjust this to adjust speed of fruit growth
    },
  },
  {
    blockID: "hb_hr:cursed_sapling",
    maxStage: 2,
    growChance: {
      numerator: 1,
      denominator: 3,
    },
  },
  {
    blockID: "hb_hr:cursed_leaves",
    maxStage: 3,
    growChance: {
      numerator: 1,
      denominator: 7, // adjust this to adjust speed of fruit growth
    },
  },
  // Add other sapling types here
];
export const logSet = new Set(["hb_hr:white_oak_log", "hb_hr:blight_log", "hb_hr:cursed_log", "hb_hr:black_log"]);
export const sapSet = new Set(["hb_hr:white_oak_sapling", "hb_hr:blight_sapling", "hb_hr:cursed_sapling", "hb_hr:black_sapling"]);
export const logMap = new Map([
  ["hb_hr:black_log", "hb_hr:stripped_black_log"],
  ["hb_hr:black_wood", "hb_hr:stripped_black_wood"],
  ["hb_hr:blight_log", "hb_hr:stripped_blight_log"],
  ["hb_hr:blight_wood", "hb_hr:stripped_blight_wood"],
  ["hb_hr:cursed_log", "hb_hr:stripped_cursed_log"],
  ["hb_hr:cursed_wood", "hb_hr:stripped_cursed_wood"],
  ["hb_hr:white_oak_log", "hb_hr:stripped_white_oak_log"],
  ["hb_hr:white_oak_wood", "hb_hr:stripped_white_oak_wood"],
]);
export const trapSet = new Set(["hb_hr:white_oak_trapdoor", "hb_hr:blight_trapdoor", "hb_hr:black_trapdoor", "hb_hr:cursed_trapdoor"]);

export const gateSet = new Set(Array.from(fenceSet).filter((item) => item.includes("_gate")));

export function applyDurabilityDamage(player, item, inventory, slotIndex) {
  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, undefined);
        player.playSound("random.break");
      } else {
        durabilityComponent.damage = newDamage;
        inventory.container.setItem(slotIndex, item);
      }
    }
  }
}

export 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 };
}

export function new_wood_handler() {
  // This handles the durality damage for all blocks (except slabs - handled in slabs.js) and removing the block above for fences and gates
  const DestroyComponent = {
    onPlayerDestroy(e) {
      const { block, player } = e;
      const aboveBlock = block.above();
      const blockBelow = block.below();

      // Remove hb_hr:fence_inventory or invisible fence gate on top if present
      if (aboveBlock.typeId.includes("_inventory") || (fenceSet.has(aboveBlock.typeId) && aboveBlock.permutation.getState("hb_hr:invisible"))) {
        aboveBlock.setType("minecraft:air");
      }

      // add hb_hr:fence_inventory if fence present below
      if (fenceSet.has(blockBelow.typeId)) {
        block.setPermutation(BlockPermutation.resolve("hb_hr:blight_fence_inventory", { "hb_hr:post": 1 }));
      }
      const inventory = player.getComponent("inventory");
      const selectedItem = inventory.container.getItem(player.selectedSlotIndex);
      if (selectedItem && (selectedItem.typeId.includes("shovel") || selectedItem.typeId.includes("hoe") || selectedItem.typeId.includes("_axe") || selectedItem.typeId.includes("_pickaxe") || selectedItem.typeId.includes("shears"))) {
        system.runTimeout(() => {
          applyDurabilityDamage(player, selectedItem, inventory, player.selectedSlotIndex);
        }, 1);
      }
    },
  };

  const customComponents = {
    "hb_hr:fence_interact": FenceInteractComponent,
    "hb_hr:on_player_destroy": DestroyComponent,
    "hb_hr:on_tick": OnTickComponent,
    "hb_hr:on_player_placed": PlaceComponent,
    "hb_hr:random_tick": randomTickComponent,
    "hb_hr:slab_interact": slabComponent,
    // "hb_hr:interact_tree": treeInteractComponent,
    "hb_hr:gate_interact": GateInteract,
    "hb_hr:gate_placed": PlaceGateComponent,
    "hb_hr:leaf_place": leafDefaultComponent,
  };

  let lastBrokenBlockType = null;
  let lastBrokenBlockIsDouble = false;

  function slabDrop(block, dimension, player) {
    if (player.getGameMode() !== "creative") {
      if (lastBrokenBlockType) {
        const blockData = lastBrokenBlockType;

        if (blockData) {
          let dropItem;

          if (lastBrokenBlockIsDouble) {
            dropItem = new ItemStack(lastBrokenBlockType, 1);
          }
          if (dropItem) {
            dimension.spawnItem(dropItem, block.location);
          }
        }
        lastBrokenBlockType = null;
        lastBrokenBlockIsDouble = false;
      }
    }
  }

  // Use this world initialization event to register all custom components
  world.beforeEvents.worldInitialize.subscribe(({ blockComponentRegistry }) => {
    for (const [componentName, componentImplementation] of Object.entries(customComponents)) {
      blockComponentRegistry.registerCustomComponent(componentName, componentImplementation);
    }
  });

  world.beforeEvents.playerBreakBlock.subscribe((eventData) => {
    const { block, player, dimension } = eventData;
    const blockBelow = block.below();
    const inventory = player.getComponent("inventory");
    const selectedItem = inventory.container.getItem(player.selectedSlotIndex);
    const { hasSilkTouch } = getRelevantEnchantments(selectedItem);

    if (selectedItem && leafSet.has(block.typeId) && selectedItem.typeId === "minecraft:shears" && !hasSilkTouch) {
      const spawnItem = block.typeId;
      system.runTimeout(() => {
        block.dimension.spawnItem(new ItemStack(spawnItem, 1), block.location);
      }, 1);
    } else if (leafSet.has(block.typeId) && !hasSilkTouch) {
      leafDrop(block, true);
    }

    if (isSlab.has(block.typeId)) {
      lastBrokenBlockType = block.typeId;
      lastBrokenBlockIsDouble = block.permutation.getState("hb_hr:double") === true;
      system.runTimeout(() => {
        if (!selectedItem) {
          slabDrop(block, dimension, player);
        } else if (selectedItem.typeId.includes("shovel") || selectedItem.typeId.includes("hoe") || selectedItem.typeId.includes("_axe") || selectedItem.typeId.includes("_pickaxe")) {
          applyDurabilityDamage(player, selectedItem, inventory, player.selectedSlotIndex);
          slabDrop(block, dimension, player);
        } else {
          slabDrop(block, dimension, player);
        }
      }, 1);
    } else if (fenceSet.has(blockBelow.typeId)) {
      system.runTimeout(() => {
        if (blockBelow.typeId.includes("hb_hr:") && blockBelow.typeId.includes("_gate")) {
          const currentStates = blockBelow.permutation.getAllStates();

          const cardinalDirection = currentStates["minecraft:cardinal_direction"];
          const newAboveStates = { ...currentStates };
          if (cardinalDirection === "south") {
            delete newAboveStates["minecraft:cardinal_direction"];
          }
          newAboveStates["hb_hr:invisible"] = true;
          block.setPermutation(BlockPermutation.resolve(blockBelow.typeId, newAboveStates));
        } else if (blockBelow.typeId.includes("hb_hr:") && !blockBelow.typeId.includes("_gate")) {
          block.setPermutation(BlockPermutation.resolve("hb_hr:blight_fence_inventory", { "hb_hr:post": 1 }));
        }
      }, 1);
    }
  });
}
