// Import necessary modules from Minecraft server API
import { world, ItemStack, system } from "@minecraft/server";
import highlightBlock from "./multiblockOutlineBlock.js";
import {
  getAdjacentBlock,
  modules,
  condenserAccept,
} from "./multiblockUtils.js";
import { openSchematicForm } from "./multiblockSchematicForm.js"; // Define cooldown duration
const ITEM_DELAY = 50; // 2.5 seconds (in ticks)
// Define block and item mappings
const blockItemMap = {
  "pb_plane:module_bender": {
    "minecraft:iron_ingot": "pb_plane:plate_iron",
    "minecraft:gold_ingot": "pb_plane:plate_gold",
    "pb_plane:plate_iron": "pb_plane:rotator",
  },
  "pb_plane:module_centrifuge": {
    "minecraft:dandelion": "pb_plane:latex",
    "minecraft:redstone": "pb_plane:redstonium",
  },
};
// Turn on and off running states for all blocks and activate entity animations
function setBlockRunningState(block, state) {
  // Set the state of the block (true/false) - For the block interacted with - core or module
  const newPermutation = block.permutation.withState(
    "pb_plane:mb_running",
    state
  );
  block.setPermutation(newPermutation);
  // If a module, update adjacent cores and if "true", animate the entity
  if (modules.includes(block.typeId)) {
    const facingDirection = block.permutation.getState(
      "minecraft:cardinal_direction"
    );
    // Get the left and right core blocks
    const leftCore = getAdjacentBlock(block, facingDirection, "left");
    const rightCore = getAdjacentBlock(block, facingDirection, "right");
    if (leftCore && leftCore.typeId === "pb_plane:machine_core") {
      const leftCorePermutation = leftCore.permutation.withState(
        "pb_plane:mb_running",
        state
      );
      leftCore.setPermutation(leftCorePermutation);
    }
    if (rightCore && rightCore.typeId === "pb_plane:machine_core") {
      const rightCorePermutation = rightCore.permutation.withState(
        "pb_plane:mb_running",
        state
      );
      rightCore.setPermutation(rightCorePermutation);
    }
    // CHeck for "true" to animate the entity
    if (state === "true") {
      block.dimension.runCommandAsync(
        `execute positioned ${block.x} ${block.y} ${block.z} run event entity @e[r=1] pb_plane:active`
      );
    }
  }
}
// Helper function to get the location in front of the block based on facing direction
function getFrontLocation(block, direction) {
  const location = block.location;
  switch (direction) {
    case "north":
      return { x: location.x + 0.5, y: location.y + 1, z: location.z + 1.2 };
    case "south":
      return { x: location.x + 0.5, y: location.y + 1, z: location.z - 0.2 };
    case "east":
      return { x: location.x - 0.2, y: location.y + 1, z: location.z + 0.5 };
    case "west":
      return { x: location.x + 1.2, y: location.y + 1, z: location.z + 0.5 };
  }
}
function consumeItem(player, selectedItem, equipment, block) {
  // Text and sound feedback for player
  player.onScreenDisplay.setActionBar("§b! [§7Item processing§b] !");
  // Handle item consumption
  if (player.getGameMode() !== "creative") {
    if (selectedItem.amount > 1) {
      selectedItem.amount -= 1;
      equipment.setEquipment("Mainhand", selectedItem);
    } else if (selectedItem.amount === 1) {
      equipment.setEquipment("Mainhand", undefined); // Clear the slot if only 1 item left
    }
  }
}
// Subscribe to the 'worldInitialize' event to register custom components
world.beforeEvents.worldInitialize.subscribe((event) => {
  event.blockComponentRegistry.registerCustomComponent(
    "pb_plane:multiblock_interaction",
    {
      onPlayerInteract(int) {
        ///// **VARIABLES AND ARRAYS** /////
        // Block and Player from interact event
        const { block, player } = int;
        // Equipment and held item
        const equipment = player.getComponent("equippable"); // Equippable component for item tracking
        const selectedItem = equipment.getEquipment("Mainhand"); // Get the players currently selected item
        // Block Data
        const connected = block.permutation.getState("pb_plane:mb_connection"); // Get the block connection state
        const blockType = block.typeId; // Get the block type
        const running = block.permutation.getState("pb_plane:mb_running"); // Get the block running state
        const facingDirection = block.permutation.getState(
          "minecraft:cardinal_direction"
        ); // Get facing direction to help get adjacent blocks
        // Set up array for cores
        const coreLocations = [];
        ///// **BLOCK INTERACTIONS** /////
        // Seperate fuel tank interactions
        if (blockType === "pb_plane:fuel_tank") {
          const fuelQty = block.permutation.getState("pb_plane:fuel_quantity"); // Loop through all groups in the condenserAccept array
          let selectedItemEntry = null;
          for (let group of condenserAccept) {
            selectedItemEntry = group.items.find(
              (item) => item.value === selectedItem?.typeId
            ); // If the item is found in this group, exit the loop
            if (selectedItemEntry) break;
          } // Check if selectedItemEntry was found in any of the groups
          if (connected !== "single" && selectedItemEntry) {
            player.onScreenDisplay.setActionBar(
              `You need to place materials into the condenser multiblock`
            );
          }
          if (connected === "single" && selectedItemEntry) {
            player.onScreenDisplay.setActionBar(
              `To add fuel, this tank needs to be connected to a condenser multiblock`
            );
          }
          if (
            selectedItem?.typeId === "pb_plane:biofuel_can_empty" &&
            fuelQty < 8
          ) {
            player.onScreenDisplay.setActionBar(
              `You need more fuel in the tank to be able to fill your fuel can.`
            );
          }
          if (
            selectedItem?.typeId === "pb_plane:biofuel_can_empty" &&
            fuelQty == 8
          ) {
            player.onScreenDisplay.setActionBar(`Fuel can filled.`); // Swap to "pb_plane:biofuel_can_full"
            const fullFuelCan = new ItemStack("pb_plane:biofuel_can_full", 1);
            equipment.setEquipment("Mainhand", fullFuelCan); // Set the block's fuelQty to 0
            block.setPermutation(
              block.permutation.withState("pb_plane:fuel_quantity", 0)
            );
          }
        } // If Module or Core in a single state - send feedback
        if (connected === "single") {
          // Assembly Core
          if (blockType === "pb_plane:assembly_core") {
            player.onScreenDisplay.setActionBar(
              "§b! [§7Assembly Station requires 4 §bAssembly Cores§7 in a 2x2 grid§b] ! "
            );
            return;
          }
          // Modules
          if (modules.includes(blockType)) {
            // Create an array to hold the coordinates of the missing cores// Check for the left core
            const leftCore = getAdjacentBlock(block, facingDirection, "left");
            if (!leftCore || leftCore.typeId !== "pb_plane:machine_core") {
              // Calculate the correct location for the left core based on direction
              const leftCoreLocation = getAdjacentBlock(
                block,
                facingDirection,
                "left"
              ).location;
              coreLocations.push({ leftCoreLocation });
              highlightBlock(leftCore);
            } // Check for the right core
            const rightCore = getAdjacentBlock(block, facingDirection, "right");
            if (!rightCore || rightCore.typeId !== "pb_plane:machine_core") {
              // Calculate the correct location for the right core based on direction
              const rightCoreLocation = getAdjacentBlock(
                block,
                facingDirection,
                "right"
              ).location;
              coreLocations.push({ rightCoreLocation });
              highlightBlock(rightCore);
            }
          } // Machine core
          if (blockType === "pb_plane:machine_core") {
            const moduleLocations = [];
            const leftBlock = getAdjacentBlock(block, facingDirection, "left");
            const farLeftBlock = getAdjacentBlock(
              block,
              facingDirection,
              "far_left"
            );
            const rightBlock = getAdjacentBlock(
              block,
              facingDirection,
              "right"
            );
            const farRightBlock = getAdjacentBlock(
              block,
              facingDirection,
              "far_right"
            );
            // Calculate the correct location for both sides of the core based on facing direction
            const leftBlockLocation = getAdjacentBlock(
              block,
              facingDirection,
              "left"
            );
            const farLeftBlockLocation = getAdjacentBlock(
              block,
              facingDirection,
              "far_left"
            );
            const rightBlockLocation = getAdjacentBlock(
              block,
              facingDirection,
              "right"
            );
            const farRightBlockLocation = getAdjacentBlock(
              block,
              facingDirection,
              "far_right"
            );
            moduleLocations.push({ leftBlockLocation });
            moduleLocations.push({ farLeftBlockLocation });
            moduleLocations.push({ rightBlockLocation });
            moduleLocations.push({ farRightBlockLocation });
            // module on left
            if (
              modules.includes(leftBlock.typeId) &&
              !modules.includes(rightBlock.typeId)
            ) {
              highlightBlock(leftBlock, "green");
              highlightBlock(farLeftBlock, "red");
              player.onScreenDisplay.setActionBar(
                `This multiblock is incomplete. Missing a core at the red highlight!`
              );
              return;
            }
            // Module on right
            if (
              !modules.includes(leftBlock.typeId) &&
              modules.includes(rightBlock.typeId)
            ) {
              highlightBlock(farRightBlock, "red");
              highlightBlock(rightBlock, "green");
              player.onScreenDisplay.setActionBar(
                `This multiblock is incomplete. Missing a core at the red highlight!`
              );
              return;
            }
            // Modules on both sides
            if (
              modules.includes(leftBlock.typeId) &&
              modules.includes(rightBlock.typeId)
            ) {
              highlightBlock(leftBlock, "red");
              highlightBlock(rightBlock, "red");
              player.onScreenDisplay.setActionBar(
                `To form your multiblock, you need a core either side of a module.`
              );
              return;
            }
            // No module found
            if (
              !modules.includes(leftBlock.typeId) &&
              !modules.includes(rightBlock.typeId)
            ) {
              highlightBlock(leftBlock, "red");
              highlightBlock(rightBlock, "red");
              player.onScreenDisplay.setActionBar(
                `This core needs to be placed next to a module.`
              );
              return;
            }
          } else {
            // Display the missing core locations to the player
            if (coreLocations.length == 2) {
              player.onScreenDisplay.setActionBar(
                `This module is incomplete. Missing machine cores at the red highlight!`
              );
            }
            if (coreLocations.length == 1) {
              player.onScreenDisplay.setActionBar(
                `This module is incomplete. Missing machine cores at the red highlight!`
              );
            }
          }
          return; // Stop further execution
        }
        // Is the module already running? - send feedback
        if (connected !== "single" && running === "true") {
          player.onScreenDisplay.setActionBar(
            "§b! [§7module is currently running§b] !"
          );
          return; // Stop further execution
        }
        // Check if the block is a core block and is connected
        if (blockType === "pb_plane:machine_core") {
          // Get the connected module (left or right)
          const side = connected === "complete_right" ? "left" : "right";
          const moduleBlock = getAdjacentBlock(block, facingDirection, side); // If the adjacent block is a module (but not the condenser or schematic)
          if (
            moduleBlock &&
            moduleBlock.typeId != "pb_plane:module_condenser" &&
            moduleBlock.typeId != "pb_plane:module_schematic"
          ) {
            // Check if the selected item is valid for the module block
            const moduleItemMap = blockItemMap[moduleBlock.typeId];
            if (moduleItemMap && selectedItem?.typeId in moduleItemMap) {
              const outputItem = moduleItemMap[selectedItem.typeId];
              // Trigger event on the connected module block
              setBlockRunningState(moduleBlock, "true");
              consumeItem(player, selectedItem, equipment, moduleBlock);
              // Handle item consumption  // Delay item spawn after cooldown and reset running state
              system.runTimeout(() => {
                if (!connected) return;
                const spawnLocation = getFrontLocation(
                  moduleBlock,
                  facingDirection
                );
                const itemToDrop = new ItemStack(outputItem, 1);
                block.dimension.spawnItem(itemToDrop, spawnLocation); // Reset running state to false and update core states
                setBlockRunningState(moduleBlock, "false");
              }, ITEM_DELAY);
              return; // Exit after successful interaction
            } else {
              player.onScreenDisplay.setActionBar(
                "§b! [§7Invalid item for this block§b] !"
              );
            }
          }
          if (
            moduleBlock &&
            moduleBlock.typeId === "pb_plane:module_condenser"
          ) {
            // Check if the selected item is valid for the module block
            const fuelTank = getAdjacentBlock(
              moduleBlock,
              facingDirection,
              "behind"
            );
            const fuelQty = fuelTank.permutation.getState(
              "pb_plane:fuel_quantity"
            );
            const tankCheck = block.permutation.getState("pb_plane:has_tank");
            if (tankCheck === "false") {
              player.onScreenDisplay.setActionBar(
                `§b! [§7Condenser needs a §bFuel Tank§7 behind it§b] !`
              );
              highlightBlock(fuelTank, "red");
              return;
            }
            if (fuelQty < 8) {
              // Find the group that contains the item
              const group = condenserAccept.find((group) =>
                group.items.some((item) => item.value === selectedItem?.typeId)
              ); // Check if the group exists and contains the selected item
              if (group) {
                const random = Math.random() * 100; // Generate a random percentage      // Check if the random number falls within the group's chance
                if (random < group.chance) {
                  // Find the selected item from the group
                  const selectedItemEntry = group.items.find(
                    (item) => item.value === selectedItem?.typeId
                  );
                  if (selectedItemEntry) {
                    // Trigger event on the connected module block
                    setBlockRunningState(moduleBlock, "true"); // Consume the item and pass in the necessary parameters
                    consumeItem(player, selectedItem, equipment, fuelTank); // Delay item spawn after cooldown and reset running state
                    system.runTimeout(() => {
                      if (!connected) return;
                      setBlockRunningState(moduleBlock, "false");
                      let newQty = fuelQty + 1;
                      if (newQty > 8) newQty = 8;
                      fuelTank.setPermutation(
                        fuelTank.permutation.withState(
                          "pb_plane:fuel_quantity",
                          newQty
                        )
                      );
                    }, ITEM_DELAY);
                    return; // Exit after successful interaction
                  }
                } else {
                  // If chance fails, give feedback to the player
                  player.onScreenDisplay.setActionBar(
                    "§b! [§7Item processing, no §bfuel§7 increase detected§b] !"
                  );
                  if (player.getGameMode() !== "creative") {
                    if (selectedItem.amount > 1) {
                      selectedItem.amount -= 1;
                      equipment.setEquipment("Mainhand", selectedItem);
                    } else if (selectedItem.amount === 1) {
                      equipment.setEquipment("Mainhand", undefined); // Clear the slot if only 1 item left
                    }
                  }
                  setBlockRunningState(moduleBlock, "false");
                }
              } else {
                player.onScreenDisplay.setActionBar(
                  "§b! [§7Invalid item for this block§b] !"
                );
              }
            } else {
              player.onScreenDisplay.setActionBar(
                "§b! [Fuel tank§7 is full§b] !"
              );
            }
          }
          if (
            moduleBlock &&
            moduleBlock.typeId === "pb_plane:module_schematic"
          ) {
            openSchematicForm(player);
          }
        }
        // Check if the block is a schematic module - opens UI for schematics
        if (blockType === "pb_plane:module_schematic") {
          openSchematicForm(player);
        }
        // Check if the block is a condenser module - handle tank checks
        if (blockType === "pb_plane:module_condenser") {
          // Check if the selected item is valid for the module block
          const fuelTank = getAdjacentBlock(block, facingDirection, "behind");
          const fuelQty = fuelTank.permutation.getState(
            "pb_plane:fuel_quantity"
          );
          const tankCheck = block.permutation.getState("pb_plane:has_tank");
          if (tankCheck === "false") {
            player.onScreenDisplay.setActionBar(
              `§b! [§7Condenser needs a §bFuel Tank§7 behind it§b] ! ${JSON.stringify(
                fuelTank
              )}`
            );
            highlightBlock(fuelTank, "red");
            return;
          }
          if (fuelQty < 8) {
            // Find the group that contains the item
            const group = condenserAccept.find((group) =>
              group.items.some((item) => item.value === selectedItem?.typeId)
            ); // Check if the group exists and contains the selected item
            if (group) {
              const random = Math.random() * 100; // Generate a random percentage    // Check if the random number falls within the group's chance
              if (random < group.chance) {
                // Find the selected item from the group
                const selectedItemEntry = group.items.find(
                  (item) => item.value === selectedItem?.typeId
                );
                if (selectedItemEntry) {
                  // Trigger event on the connected module block
                  setBlockRunningState(block, "true"); // Consume the item and pass in the necessary parameters
                  consumeItem(player, selectedItem, equipment, fuelTank); // Delay item spawn after cooldown and reset running state
                  system.runTimeout(() => {
                    if (!connected) return;
                    setBlockRunningState(block, "false");
                    let newQty = fuelQty + 1;
                    if (newQty > 8) newQty = 8;
                    fuelTank.setPermutation(
                      fuelTank.permutation.withState(
                        "pb_plane:fuel_quantity",
                        newQty
                      )
                    );
                  }, ITEM_DELAY);
                  return; // Exit after successful interaction
                }
              } else {
                // If chance fails, give feedback to the player
                player.onScreenDisplay.setActionBar(
                  "§b! [§7Item processing, no §bfuel§7 increase detected§b] !"
                );
                if (player.getGameMode() !== "creative") {
                  if (selectedItem.amount > 1) {
                    selectedItem.amount -= 1;
                    equipment.setEquipment("Mainhand", selectedItem);
                  } else if (selectedItem.amount === 1) {
                    equipment.setEquipment("Mainhand", undefined); // Clear the slot if only 1 item left
                  }
                }
                setBlockRunningState(block, "false");
              }
            } else {
              player.onScreenDisplay.setActionBar(
                "§b! [§7Invalid item for this block§b] !"
              );
            }
          } else {
            player.onScreenDisplay.setActionBar(
              "§b! [Fuel tank§7 is full§b] !"
            );
          }
        }
        // Check if the block is a module with an item conversion - Bender and Centrifuge
        if (blockItemMap[blockType]) {
          const itemMap = blockItemMap[blockType];
          const outputItem = itemMap[selectedItem?.typeId]; // Trigger event when interacting directly with the module block only if item is valid
          if (outputItem) {
            setBlockRunningState(block, "true");
            consumeItem(player, selectedItem, equipment, block); // Handle item consumption// Spawn the resulting item after a delay and reset block state
            system.runTimeout(() => {
              const spawnLocation = getFrontLocation(block, facingDirection);
              const itemToDrop = new ItemStack(outputItem, 1);
              block.dimension.spawnItem(itemToDrop, spawnLocation);
              setBlockRunningState(block, "false");
            }, ITEM_DELAY);
          } else {
            player.onScreenDisplay.setActionBar(
              "§b! [§7Invalid item for this block§b] !"
            );
          }
        }
      },
    }
  );
});
