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

const excludeFromRevert = [
  "hb_hr:gravestone",
  "minecraft:pink_petals",
  "minecraft:structure_void",
  "minecraft:barrier",
  "minecraft:torch",
  "minecraft:soul_torch",
  "minecraft:redstone_torch",
  "minecraft:web",
  "minecraft:trip_wire",
  "minecraft:tripwire_hook",
  "minecraft:unlit_redstone_torch",
  "minecraft:redstone_wire",
  "minecraft:spruce_sign",
  "minecraft:birch_sign",
  "minecraft:jungle_sign",
  "minecraft:acacia_sign",
  "minecraft:darkoak_sign",
  "minecraft:crimson_sign",
  "minecraft:warped_sign",
  "minecraft:pale_oak_hanging_sign",
  "minecraft:pale_oak_sign",
  "minecraft:mangrove_sign",
  "minecraft:acacia_hanging_sign",
  "minecraft:bamboo_hanging_sign",
  "minecraft:bamboo_sign",
  "minecraft:birch_hanging_sign",
  "minecraft:cherry_hanging_sign",
  "minecraft:cherry_sign",
  "minecraft:crimson_hanging_sign",
  "minecraft:dark_oak_hanging_sign",
  "minecraft:jungle_hanging_sign",
  "minecraft:mangrove_hanging_sign",
  "minecraft:oak_hanging_sign",
  "minecraft:spruce_hanging_sign",
  "minecraft:warped_hanging_sign",
  "minecraft:roup",
  "minecraft:crimson_standing_sign",
  "minecraft:warped_standing_sign",
  "minecraft:crimson_wall_sign",
  "minecraft:warped_wall_sign",
  "minecraft:standing_sign",
  "minecraft:spruce_standing_sign",
  "minecraft:birch_standing_sign",
  "minecraft:jungle_standing_sign",
  "minecraft:acacia_standing_sign",
  "minecraft:darkoak_standing_sign",
  "minecraft:mangrove_trapdoor",
  "minecraft:bamboo_trapdoor",
  "minecraft:cherry_trapdoor",
  "minecraft:crimson_trapdoor",
  "minecraft:warped_trapdoor",
  "minecraft:iron_trapdoor",
  "minecraft:acacia_trapdoor",
  "minecraft:birch_trapdoor",
  "minecraft:dark_oak_trapdoor",
  "minecraft:jungle_trapdoor",
  "minecraft:spruce_trapdoor",
  "minecraft:pale_oak_trapdoor",
  "minecraft:copper_trapdoor",
  "minecraft:exposed_copper_trapdoor",
  "minecraft:oxidized_copper_trapdoor",
  "minecraft:waxed_copper_trapdoor",
  "minecraft:waxed_exposed_copper_trapdoor",
  "minecraft:waxed_oxidized_copper_trapdoor",
  "minecraft:waxed_weathered_copper_trapdoor",
  "minecraft:weathered_copper_trapdoor",
  "minecraft:copper_door",
  "minecraft:acacia_door",
  "minecraft:birch_door",
  "minecraft:dark_oak_door",
  "minecraft:iron_door",
  "minecraft:jungle_door",
  "minecraft:wooden_door",
  "minecraft:spruce_door",
  "minecraft:crimson_door",
  "minecraft:warped_door",
  "minecraft:exposed_copper_door",
  "minecraft:oxidized_copper_door",
  "minecraft:waxed_copper_door",
  "minecraft:waxed_exposed_copper_door",
  "minecraft:waxed_oxidized_copper_door",
  "minecraft:waxed_weathered_copper_door",
  "minecraft:weathered_copper_door",
  "minecraft:pale_oak_door",
  "minecraft:mangrove_door",
  "minecraft:bamboo_door",
  "minecraft:cherry_door",
  "minecraft:crimson_door",
  "minecraft:warped_door",
  "minecraft:iron_door",
  "minecraft:copper_door",
  "minecraft:exposed_copper_door",
  "minecraft:oxidized_copper_door",
  "minecraft:waxed_copper_door",
  "minecraft:waxed_exposed_copper_door",
  "minecraft:waxed_oxidized_copper_door",
  "minecraft:waxed_weathered_copper_door",
  "minecraft:weathered_copper_door",
  "minecraft:mangrove_fence",
  "minecraft:mangrove_fence_gate",
  "minecraft:bamboo_fence_gate",
  "minecraft:bamboo_fence",
  "minecraft:cherry_fence_gate",
  "minecraft:cherry_fence",
  "minecraft:acacia_fence_gate",
  "minecraft:birch_fence_gate",
  "minecraft:crimson_fence",
  "minecraft:warped_fence",
  "minecraft:crimson_fence_gate",
  "minecraft:warped_fence_gate",
  "minecraft:dark_oak_fence_gate",
  "minecraft:jungle_fence_gate",
  "minecraft:nether_brick_fence",
  "minecraft:spruce_fence_gate",
  "minecraft:pale_oak_fence",
  "minecraft:pale_oak_fence_gate",
  "hb_hr:blight_trapdoor",
  "hb_hr:black_trapdoor",
  "hb_hr:cursed_trapdoor",
  "hb_hr:blight_door",
  "hb_hr:black_door",
  "hb_hr:cursed_door",
  "minecraft:bell",
  "minecraft:flower_pot",
  "hb_hr:grim_stone_bricks_wall",
  "hb_hr:blight_fence_gate",
  "hb_hr:black_fence_gate",
  "hb_hr:cursed_fence_gate",
  "hb_hr:blight_fence",
  "hb_hr:black_fence",
  "hb_hr:cursed_fence",
  "hb_hr:bone_pile_b2_0",
  "hb_hr:bone_pile_b2_1",
  "hb_hr:bone_pile_b2_2",
  "hb_hr:bone_pile_small_0",
  "hb_hr:bone_pile_small_1",
  "hb_hr:bone_pile_small_2",
  "hb_hr:bone_pile_small_3",
  "hb_hr:bone_pile_small_4",
  "hb_hr:mushroom_litter",
  "hb_hr:cursed_grass",
  "hb_hr:gravestone",
  "hb_hr:dead_grass",
  "hb_hr:dead_bush",
  "hb_hr:grim_stone_chunks",
  "hb_hr:cursed_grass",
  "hb_hr:cursed_tall_grass",
  "hb_hr:cursed_bush",
  "hb_hr:black_rose",
  "hb_hr:black_grass",
  "hb_hr:black_tall_grass",
];

// Configuration for grass behavior.
const grassConfig = {
  // Blocks that grass can spread onto (e.g. dirt).
  spreadTargets: ["minecraft:dirt"],
  // Block to revert to if grass is covered by a full block.
  revertBlock: "minecraft:dirt",
  // Chance for the grass block to grow a plant on top (per random tick).
  plantGrowthChance: 0.01, // 10% chance per tick.
  // Array of possible plant block types that may appear on top.
  plants: [],
  // Chance for grass to spread to each direct horizontal neighbour.
  spreadChance: 0.2,
};
export function grassBlock() {
  world.beforeEvents.worldInitialize.subscribe((event) => {
    event.blockComponentRegistry.registerCustomComponent("hb_hr:grassBlock", {
      onRandomTick(data) {
        const { block } = data;
        if (!block) return;
        const dimension = block.dimension;
        const loc = block.location;

        // Check the block directly above.
        const aboveBlock = block.above();

        // Revert if there is a solid block on top.
        if (!(block.typeId.includes("hb_hr:") && block.typeId.includes("snowed_in")) && aboveBlock && isSolidBlock(aboveBlock) && (aboveBlock.typeId == "minecraft:snow" || aboveBlock.typeId == "minecraft:snow_layer" || aboveBlock.typeId == "minecraft:powder_snow")) {
          if (block.typeId !== grassConfig.revertBlock && !excludeFromRevert.includes(aboveBlock.typeId)) {
            dimension.setBlockType(loc, block.typeId + "_snowed_in");
          }
          return; // Stop further processing.
        }
        if (block.typeId.includes("hb_hr:") && block.typeId.includes("snowed_in") && aboveBlock && isSolidBlock(aboveBlock) && !(aboveBlock.typeId == "minecraft:snow" || aboveBlock.typeId == "minecraft:snow_layer" || aboveBlock.typeId == "minecraft:powder_snow")) {
          if (block.typeId !== grassConfig.revertBlock && !excludeFromRevert.includes(aboveBlock.typeId)) {
            dimension.setBlockType(loc, grassConfig.revertBlock);
          }
          return; // Stop further processing.
        }
        if (block.typeId.includes("hb_hr:") && block.typeId.includes("snowed_in") && aboveBlock && !(aboveBlock.typeId == "minecraft:snow" || aboveBlock.typeId == "minecraft:snow_layer" || aboveBlock.typeId == "minecraft:powder_snow")) {
          if (block.typeId !== grassConfig.revertBlock && !excludeFromRevert.includes(aboveBlock.typeId)) {
            dimension.setBlockType(loc, block.typeId.replace(/_snowed_in$/, ""));
          }
          return; // Stop further processing.
        }
        if (!(block.typeId.includes("hb_hr:") && block.typeId.includes("snowed_in")) && aboveBlock && isSolidBlock(aboveBlock)) {
          if (block.typeId !== grassConfig.revertBlock && !excludeFromRevert.includes(aboveBlock.typeId)) {
            dimension.setBlockType(loc, grassConfig.revertBlock);
          }
          return; // Stop further processing.
        }

        // If the block above is air or non-solid, try growing a plant on top.
        if (Math.random() < grassConfig.plantGrowthChance) {
          // Choose a random plant from the array.
          const plant = grassConfig.plants[Math.floor(Math.random() * grassConfig.plants.length)];
          if (plant) {
            dimension.setBlockType(abovePos, plant);
          }
        }

        // Spread to direct horizontal neighbours.
        const neighbours = [
          { x: loc.x + 1, y: loc.y, z: loc.z },
          { x: loc.x - 1, y: loc.y, z: loc.z },
          { x: loc.x, y: loc.y, z: loc.z + 1 },
          { x: loc.x, y: loc.y, z: loc.z - 1 },

          { x: loc.x + 1, y: loc.y + 1, z: loc.z },
          { x: loc.x - 1, y: loc.y + 1, z: loc.z },
          { x: loc.x, y: loc.y + 1, z: loc.z + 1 },
          { x: loc.x, y: loc.y + 1, z: loc.z - 1 },

          { x: loc.x + 1, y: loc.y - 1, z: loc.z },
          { x: loc.x - 1, y: loc.y - 1, z: loc.z },
          { x: loc.x, y: loc.y - 1, z: loc.z + 1 },
          { x: loc.x, y: loc.y - 1, z: loc.z - 1 },
        ];
        for (const pos of neighbours) {
          const neighborBlock = dimension.getBlock(pos);
          // Only spread if the neighbour is a valid target.
          if (neighborBlock && grassConfig.spreadTargets.includes(neighborBlock.typeId)) {
            const neighborAbovePos = { x: pos.x, y: pos.y + 1, z: pos.z };
            const neighborAbove = dimension.getBlock(neighborAbovePos);
            // Only spread if the block above is not solid.
            if (neighborAbove && !isSolidBlock(neighborAbove)) {
              if (Math.random() < grassConfig.spreadChance) {
                dimension.setBlockType(pos, block.typeId);
              }
            }
          }
        }
      },
    });
  });
}
/**
 * Helper: Determines whether a block is considered "solid" for our purposes.
 * A block is considered non-solid if it is:
 *   - Air.
 *   - Tagged as "plant".
 *   - Tagged as "fertilize_area".
 *
 * This function assumes that if the block has a getTags() method,
 * it will return an array of string tags.
 */
function isSolidBlock(block) {
  // Air is non-solid.
  // if (block.typeId === "minecraft:barrier") return false;
  if (block.typeId === "minecraft:air") return false;

  // Check for block tags if available.
  if (typeof block.getTags === "function") {
    const tags = block.getTags();
    if (tags.includes("minecraft:plant") || tags.includes("minecraft:fertilize_area")) {
      return false;
    }
  }

  // Otherwise, assume the block is solid.
  return true;
}
