// Import necessary modules from the Minecraft server API
// These modules provide access to system scheduling, world state, block permutations,
// item stacks, and block volume utilities.
import { system, world, BlockPermutation, ItemStack, BlockVolume } from "@minecraft/server";
import { getEntityRotation } from "../utilities/helpers";

// Define all the bench block types that our handler will recognize
const benchTypes = ["hb_cb:single_bench_oak_block", "hb_cb:single_bench_acacia_block", "hb_cb:single_bench_birch_block", "hb_cb:single_bench_cherry_block", "hb_cb:single_bench_crimson_block", "hb_cb:single_bench_dark_oak_block", "hb_cb:single_bench_jungle_block", "hb_cb:single_bench_mangrove_block", "hb_cb:single_bench_pale_block", "hb_cb:single_bench_spruce_block", "hb_cb:single_bench_warped_block"];
const stumpChairTypes = ["hb_cb:stump_chair_oak_block", "hb_cb:stump_chair_acacia_block", "hb_cb:stump_chair_birch_block", "hb_cb:stump_chair_cherry_block", "hb_cb:stump_chair_crimson_block", "hb_cb:stump_chair_dark_oak_block", "hb_cb:stump_chair_jungle_block", "hb_cb:stump_chair_mangrove_block", "hb_cb:stump_chair_pale_block", "hb_cb:stump_chair_spruce_block", "hb_cb:stump_chair_warped_block"];

// Custom component implementation for bench interaction and placement
export const benchHandlerBlockComponent = {
  // Called when a player interacts with the bench block
  onPlayerInteract(e) {
    const { block, player } = e; // Destructure the event to get block and player
    // Search for nearby single_bench entities at the block's location
    let nearbyEntities = world.getDimension(player.dimension.id).getEntities({
      type: "hb_cb:single_bench",
      location: { x: block.center().x, y: block.center().y - 0.2, z: block.center().z },
      minDistance: 0,
      maxDistance: 0.2,
    });
    // If no bench entity exists, spawn one and put the player on it
    if (nearbyEntities.length === 0 || !nearbyEntities) {
      let single_bench = player.dimension.spawnEntity("hb_cb:single_bench", { x: block.center().x, y: block.center().y - 0.2, z: block.center().z });
      const rideable = single_bench.getComponent("minecraft:rideable");
      rideable.addRider(player);
      return;
    } else return;
  },
  // Called before placing the block to adjust orientation based on player rotation
  beforeOnPlayerPlace(e) {
    const { player, permutationToPlace, block } = e;
    // Prevent default placement logic for our custom bench types
    if (benchTypes.includes(block.typeId)) {
      e.cancel = true;
      return;
    }
    // Determine the player's facing direction
    let yRotation = getEntityRotation(player);
    let orientation;
    switch (yRotation) {
      case 0:
        orientation = "north";
        break;
      case 90:
        orientation = "east";
        break;
      case 180:
        orientation = "south";
        break;
      case 270:
        orientation = "west";
        break;
      default:
        break;
    }

    // Define block state to set its facing direction
    const baseStates = {
      "minecraft:block_face": orientation,
    };

    // Create a new permutation with the correct orientation
    const newPerm = BlockPermutation.resolve(permutationToPlace.type.id, baseStates);

    // Apply the oriented permutation to the placement event
    e.permutationToPlace = newPerm;
  },
};
// Custom component implementation for bench interaction and placement
export const stumpChairHandlerBlockComponent = {
  // Called when a player interacts with the bench block
  onPlayerInteract(e) {
    const { block, player } = e; // Destructure the event to get block and player
    // Search for nearby single_bench entities at the block's location
    let nearbyEntities = world.getDimension(player.dimension.id).getEntities({
      type: "hb_cb:stump_chair",
      location: { x: block.center().x, y: block.center().y - 0.2, z: block.center().z },
      minDistance: 0,
      maxDistance: 0.2,
    });
    // If no bench entity exists, spawn one and put the player on it
    if (nearbyEntities.length === 0 || !nearbyEntities) {
      let single_bench = player.dimension.spawnEntity("hb_cb:stump_chair", { x: block.center().x, y: block.center().y - 0.2, z: block.center().z });
      const rideable = single_bench.getComponent("minecraft:rideable");
      rideable.addRider(player);
      return;
    } else return;
  },
  // Called before placing the block to adjust orientation based on player rotation
  beforeOnPlayerPlace(e) {
    const { player, block } = e;
    // Prevent default placement logic for our custom bench types
    if (stumpChairTypes.includes(block.typeId)) {
      e.cancel = true;
      return;
    }
  },
};

// Register custom components to use in world initialization
const customComponents = {
  "hb_cb:bench_handler": benchHandlerBlockComponent,
  "hb_cb:stump_chair_handler": stumpChairHandlerBlockComponent,
};

let curTick = 0;
const INIT_TIME = 0;
// Function to initialize bench-related tick updates and event subscriptions
export function singleBenchBlock(player) {
  // Run interval logic every game tick (20 times per second)
  system.runInterval(() => {
    try {
      if (curTick > INIT_TIME) {
        const allPlayers = world.getAllPlayers();
        allPlayers.forEach((player) => {
          if (!player.isValid()) return;
          else {
            changeOldBenchItems(player);
            try {
              // Clean up old benches and bench blocks
              despawnOldBenches(player);
              despawnOldBenchBlocks(player);
            } catch (error) {}
          }
        });
      }
      curTick++;
    } catch (e) {
      console.warn(e);
    }
  }, 20);

  // Subscribe to block break events to handle items drops
  world.afterEvents.playerBreakBlock.subscribe((event) => {
    const block = event.brokenBlockPermutation;
    const usedItem = event.itemStackAfterBreak;
    const player = event.player;
    const benchAndStumpChairTypes = benchTypes.concat(stumpChairTypes);
    if (!benchAndStumpChairTypes.includes(block.type.id)) return;
    if (usedItem == undefined) return;
    // If the tool has Silk Touch, do not drop the item
    if (usedItem.getComponent("enchantable") != undefined) {
      const enchants = usedItem.getComponent("enchantable");
      if (enchants.getEnchantment("silk_touch") != undefined) {
        return;
      }
    }
  });

  // Listen for script events to despawn bench entities when the block is gone
  system.afterEvents.scriptEventReceive.subscribe((event) => {
    if (event.sourceEntity == undefined) return;
    else {
      if (event.sourceEntity.typeId == "hb_cb:single_bench" || event.sourceEntity.typeId == "hb_cb:stump_chair") {
        let sourceEntity = event.sourceEntity;
        switch (event.id) {
          case "hb_cb:bench_despawn_check":
            const benchBlock = sourceEntity.dimension.getBlock(sourceEntity.location);
            if (!benchBlock) return;
            if (!benchTypes.includes(benchBlock.typeId)) sourceEntity.remove();
            break;
          case "hb_cb:stump_chair_despawn_check":
            const stumpChairBlock = sourceEntity.dimension.getBlock(sourceEntity.location);
            if (!stumpChairBlock) return;
            if (!stumpChairTypes.includes(stumpChairBlock.typeId)) sourceEntity.remove();
            break;
        }
      }
    }
  });

  // Register our custom block components when the world initializes
  world.beforeEvents.worldInitialize.subscribe(({ blockComponentRegistry }) => {
    for (const [componentName, componentImplementation] of Object.entries(customComponents)) {
      blockComponentRegistry.registerCustomComponent(componentName, componentImplementation);
    }
  });
}

// Remove old bench entities around the player and drop items
function despawnOldBenches(player) {
  let nearbyEntities = world.getDimension(player.dimension.id).getEntities({
    type: "hb_cb:bench",
    location: player.location,
    minDistance: 0,
    maxDistance: 5,
  });
  if (nearbyEntities.length === 0 || !nearbyEntities) return;
  nearbyEntities.forEach((bench) => {
    // Drop 3 oak bench blocks when despawning
    const benchItem = new ItemStack("hb_cb:single_bench_oak_block");
    benchItem.amount = 3;
    player.dimension.spawnItem(benchItem, bench.location);
    bench.remove();
  });
}

// Remove old bench block types in a volume around the player
function despawnOldBenchBlocks(player) {
  const volume = new BlockVolume({ x: player.location.x + 3, y: player.location.y + 2, z: player.location.z + 3 }, { x: player.location.x - 3, y: player.location.y - 2, z: player.location.z - 3 });

  const locations = volume.getBlockLocationIterator();

  for (const location of locations) {
    const block = player.dimension.getBlock(location);
    if (!block) continue;
    const blockType = block.typeId;
    if (blockType != "hb_cb:bench_block") continue;
    // Replace bench_block with air
    block.setType("minecraft:air");
  }
}

// Replace old bench items in player inventories with single bench oak blocks
function changeOldBenchItems(player) {
  const playerContainer = player.getComponent("inventory").container;
  for (let i = 0; i < playerContainer.size; i++) {
    const item = playerContainer.getItem(i);
    if (!item) continue;
    if (item.typeId == "hb_cb:bench_item") {
      let replaceItem = new ItemStack("hb_cb:single_bench_oak_block");
      playerContainer.setItem(i, replaceItem);
    }
  }
}
