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

// Map of double plant block types to their corresponding drop item type IDs.
// Add more mappings as needed.
const dropMapping = {
  "hb_hr:cursed_tall_grass": "hb_hr:cursed_grass",
};

export function doublePlant() {
  // Register the custom block component for double plants when the world initializes.
  world.beforeEvents.worldInitialize.subscribe((eventData) => {
    eventData.blockComponentRegistry.registerCustomComponent("hb_hr:double_plant", {
      // Integrity check on random ticks: if one half is missing or altered, remove the remaining half.
      onRandomTick(event) {
        const block = event.block;
        const isUpper = block.permutation.getState("hb_hr:upper_block_bit");
        if (isUpper) {
          // Upper half: ensure the lower block exists, is tagged properly, and its state is false.
          const lowerBlock = block.below();
          if (
            !lowerBlock ||
            !lowerBlock.hasTag("hb_hr:double_plant") ||
            lowerBlock.permutation.getState("hb_hr:upper_block_bit") !== false
          ) {
            // world.sendMessage("destroy upper");
            block.setPermutation(BlockPermutation.resolve("minecraft:air"));
          }
        } else {
          // Lower half: ensure the upper block exists and its state is true.
          const upperBlock = block.above();
          if (
            !upperBlock ||
            upperBlock.permutation.getState("hb_hr:upper_block_bit") !== true
          ) {
            // world.sendMessage("destroy lower");
            block.setPermutation(BlockPermutation.resolve("minecraft:air"));
          }
        }
      },
      // Before a player places a double plant block, verify that the placement is valid
      // (i.e. the block above is in range and empty, and the block below exists to support the plant).
      beforeOnPlayerPlace(event) {
        const { block, dimension, permutationToPlace } = event;
        const loc = block.location;
        if (loc.y + 1 >= dimension.heightRange.max) {
          event.cancel = true;
          return;
        }
        let blockBelow;
        try {
          blockBelow = block.below();
        } catch {}
        if (!blockBelow || blockBelow.isAir || blockBelow.typeId === permutationToPlace.type.id || blockBelow.isLiquid) {
          event.cancel = true;
          return;
        }
        let blockAbove;
        try {
          blockAbove = dimension.getBlock({ x: loc.x, y: loc.y + 1, z: loc.z });
        } catch {}
        if (!blockAbove || !blockAbove.isAir || blockAbove.isLiquid) {
          event.cancel = true;
          return;
        }
        // Schedule the placement of the upper half.
        system.runTimeout(() => {
          // world.sendMessage("placed");
          placeDoublePlant(block, blockAbove);
        }, 1);
      }
      // Additional interactions can be added here if needed.
    });
  });

  // Listen for player break events on double plant blocks and ensure that breaking one half
  // causes both halves to be removed.
  world.beforeEvents.playerBreakBlock.subscribe((data) => {
    const block = data.block;
    if (!block.hasTag("hb_hr:double_plant")) return;
    data.cancel = true; // Cancel normal break logic.

    const player = data.player;
    const equippable = player.getComponent("equippable");
    const mainhandItem = equippable?.getEquipment(EquipmentSlot.Mainhand);
    const usingScissors = mainhandItem && (mainhandItem.typeId === "minecraft:shears");
    
    if (usingScissors) {
      // Look up the drop in the map based on the block type.
      const dropItemId = dropMapping[block.typeId];
      if (dropItemId) {
        const drop = new ItemStack(dropItemId, 1);
        system.run(() => {
          block.dimension.spawnItem(drop, block.location);
        });
      }
    }
    
    // Break both halves of the double plant.
    system.run(() => {
      breakDoublePlant(block);
    });
  });

  // Listen for explosions that affect double plant blocks and remove both halves.
  world.beforeEvents.explosion.subscribe((event) => {
    const plantBlocks = event.getImpactedBlocks().filter((block) =>
      block.permutation.hasTag("hb_hr:double_plant")
    );
    for (const block of plantBlocks) {
      system.runTimeout(() => {
        breakDoublePlant(block);
      }, 1);
    }
  });

  // Function to set up the double plant by modifying the lower block and the block above.
  function placeDoublePlant(lowerBlock, upperBlock) {
    // Set the lower block: mark as double plant with the "upper_block_bit" set to false.
    lowerBlock.setPermutation(lowerBlock.permutation.withState("hb_hr:upper_block_bit", false));
    // Set the upper block: mark it as the top half with "upper_block_bit" set to true.
    upperBlock.setPermutation(BlockPermutation.resolve(lowerBlock.typeId));
    upperBlock.setPermutation(upperBlock.permutation.withState("hb_hr:upper_block_bit", true));
  }

  // Function to properly break the double plant.
  // Given a broken block, it determines the other half and then sets both to air.
  function breakDoublePlant(brokenBlock) {
    let otherBlock;
    const isUpper = brokenBlock.permutation.getState("hb_hr:upper_block_bit");
    if (isUpper) {
      try {
        otherBlock = brokenBlock.below();
      } catch {}
    } else {
      try {
        otherBlock = brokenBlock.above();
      } catch {}
    }
    // Remove the other half if it exists and is part of the double plant.
    if (otherBlock && otherBlock.hasTag("hb_hr:double_plant")) {
      otherBlock.setPermutation(BlockPermutation.resolve("minecraft:air"));
    }

    // Remove the broken block using a fill command with the "destroy" option.
    brokenBlock.dimension.runCommand(
      "fill " +
        brokenBlock.location.x +
        " " +
        brokenBlock.location.y +
        " " +
        brokenBlock.location.z +
        " " +
        brokenBlock.location.x +
        " " +
        brokenBlock.location.y +
        " " +
        brokenBlock.location.z +
        " air destroy"
    );
  }
}
