import { TimeOfDay, system, world, ItemStack, StructureAnimationMode, StructureRotation, StructureSaveMode } from "@minecraft/server";
import { checkBelowEntityDespawn, getStringBefore, checkLocation, getEntityRotation, getLocationbyFacingBlock, stringBetween, getGamemode, getElementPosition, getElementPositionArrayWithObjects } from "./helpers";
import { getDiscIndex } from "../utilities/backpack_handler";
import { cameraCutscene } from "../events/camera";
import { ActionFormData } from "@minecraft/server-ui";

export class miniJukeboxHandler {
  static initialized = false;
  constructor() {
    this.initialize();
  }

  initialize() {
    if (!miniJukeboxHandler.initialized) {
      miniJukeboxHandler.initialized = true;
      this.processSubscriptions();
    } else {
    }
  }
  processSubscriptions() {
    let curTick = 0;
    const INIT_TIME = 0;

    system.runInterval(() => {
      try {
        if (curTick > INIT_TIME) {
          const allPlayers = world.getAllPlayers();
          allPlayers.forEach((player) => {
            if (!player.isValid()) return;
            else {
              checkBelowEntityDespawn(player, "mini_jukebox");
            }
          });
        }
        curTick++;
      } catch (e) {
        console.warn(e);
      }
    }, 10);

    world.afterEvents.itemUse.subscribe((event) => {
      const player = event.source;
      const typeId = player.typeId;
      if (typeId !== "minecraft:player") {
        return;
      }
      const holdingItem = player.getComponent("equippable").getEquipment("Mainhand");
      if (holdingItem == undefined) {
        return;
      }
      if (holdingItem.typeId == "hb_cb:mini_jukebox_item") this.spawnMiniJukebox(player, holdingItem);
    });
    system.afterEvents.scriptEventReceive.subscribe((event) => {
      if (event.sourceEntity == undefined) return;
      else {
        if (event.sourceEntity.typeId.includes("hb_cb:") && event.sourceEntity.typeId.includes("mini_jukebox")) {
          let mini_jukebox = event.sourceEntity;
          switch (event.id) {
            // — inside your switch…case block —
            case "hb_cb:reset_slot_0_controller":
              const old0Disc = mini_jukebox.getProperty("hb_cb:slot_0_disc") ?? 0;
              if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_0_disc", 0);
              system.runTimeout(() => {
                if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_0_disc", old0Disc);
              }, 5);

              break;
            case "hb_cb:reset_slot_1_controller":
              const old1Disc = mini_jukebox.getProperty("hb_cb:slot_1_disc") ?? 0;
              if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_1_disc", 0);
              system.runTimeout(() => {
                if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_1_disc", old1Disc);
              }, 5);

              break;
            case "hb_cb:reset_slot_2_controller":
              const old2Disc = mini_jukebox.getProperty("hb_cb:slot_2_disc") ?? 0;
              if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_2_disc", 0);
              system.runTimeout(() => {
                if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_2_disc", old2Disc);
              }, 5);

              break;
            case "hb_cb:reset_slot_3_controller":
              const old3Disc = mini_jukebox.getProperty("hb_cb:slot_3_disc") ?? 0;
              if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_3_disc", 0);
              system.runTimeout(() => {
                if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_3_disc", old3Disc);
              }, 5);

              break;
            case "hb_cb:reset_slot_4_controller":
              const old4Disc = mini_jukebox.getProperty("hb_cb:slot_4_disc") ?? 0;
              if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_4_disc", 0);
              system.runTimeout(() => {
                if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_4_disc", old4Disc);
              }, 5);

              break;
            case "hb_cb:check_playing":
              const slot_counter = mini_jukebox.getProperty("hb_cb:slot_counter");
              if (slot_counter == 0) {
                for (let i = 0; i <= 4; i++) {
                  const propKey = `hb_cb:slot_${i}_disc`;

                  const SlotValue = mini_jukebox.getProperty(propKey) ?? 0;

                  if (SlotValue != 0) {
                    if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_counter", SlotValue);
                    break;
                  }
                }
              }
              // // world.sendMessage("Checking jukebox slots…");

              const inv = mini_jukebox.getComponent("inventory").container;
              const totalSlots = 5;

              // world.sendMessage("palying slot:  " + (mini_jukebox.getProperty("hb_cb:slot_counter") - 1).toString());
              // DEBUG: show each slot’s item & property
              for (let slot = 0; slot < totalSlots; slot++) {
                const item = inv.getItem(slot);
                const typeId = item?.typeId ?? "<empty>";
                const propDisc = mini_jukebox.getProperty(`hb_cb:slot_${slot}_disc`) ?? 0;
                // world.sendMessage(`Slot ${slot} → inventory item: ${typeId}, ` + `hb_cb:slot_${slot}_disc property: ${propDisc}`);
              }
              // read the “real” disc index in each slot
              const itemDiscs = Array.from({ length: totalSlots }, (_, i) => getDiscIndex(inv.getItem(i)?.typeId ?? ""));

              // sync all slots, track which one changed last
              let changedSlot = -1;
              for (let slot = 0; slot < totalSlots; slot++) {
                const key = `hb_cb:slot_${slot}_disc`;
                const storedDisc = mini_jukebox.getProperty(key) ?? 0;
                const actualDisc = itemDiscs[slot];

                if (storedDisc !== actualDisc) {
                  if (mini_jukebox.isValid()) mini_jukebox.setProperty(key, actualDisc);
                  // world.sendMessage(`Slot ${slot} updated from ${storedDisc} → ${actualDisc}.`);
                  changedSlot = slot;
                  // world.sendMessage("changedSlot: " + changedSlot + ", slot: " + slot);
                }
              }
              system.runTimeout(() => {
                if (!mini_jukebox.isValid()) return;
                if (changedSlot >= 0 && !mini_jukebox.hasTag("hb_cb:changing_disc_slot")) {
                  // world.sendMessage(`Detected change in slot ${changedSlot}—resetting playback…`);

                  // 1) stop
                  if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_counter", 0);

                  // 2) after a short delay, find the next non-empty slot (starting at changedSlot)
                  system.runTimeout(() => {
                    let targetSlot = changedSlot;
                    let discToPlay = itemDiscs[targetSlot];

                    // if the changed slot is empty, scan forward
                    if (discToPlay <= 0) {
                      for (let i = changedSlot + 1; i < totalSlots; i++) {
                        if (itemDiscs[i] > 0) {
                          targetSlot = i;
                          discToPlay = itemDiscs[i];
                          break;
                        }
                      }
                    }
                    // wrap around if still empty
                    if (discToPlay <= 0) {
                      for (let i = 0; i < changedSlot; i++) {
                        if (itemDiscs[i] > 0) {
                          targetSlot = i;
                          discToPlay = itemDiscs[i];
                          break;
                        }
                      }
                    }

                    // set and play (or log if truly empty)
                    // world.sendMessage("changed slot: " + (targetSlot).toString());
                    if (mini_jukebox.isValid()) mini_jukebox.setProperty("hb_cb:slot_counter", targetSlot + 1);
                    if (discToPlay > 0) {
                      if (mini_jukebox.isValid()) mini_jukebox.setProperty(`hb_cb:slot_${targetSlot}_disc`, discToPlay);
                      // // world.sendMessage(`hb_cb:slot_${targetSlot}_disc` + ": " + discToPlay);
                      // world.sendMessage(`Now playing slot ${targetSlot} (disc ${discToPlay}).`);
                    } else {
                      if (mini_jukebox.isValid()) mini_jukebox.setProperty(`hb_cb:slot_${targetSlot}_disc`, 0);
                      // // world.sendMessage(`hb_cb:slot_${targetSlot}_disc` + ": " + 0);
                      // world.sendMessage(`Now playing slot ${targetSlot} (disc ${0}).`);
                      // // world.sendMessage("All slots empty—nothing to play.");
                    }
                  }, 5);
                }
              }, 20);

              break;

            case "hb_cb:despawn_tick_hit_trigger":
              if (mini_jukebox.getProperty("hb_cb:despawn_tick") < 4) {
                mini_jukebox.runCommand("/playsound break.cherry_wood @a[r=10] ~~~ 1 1");
                mini_jukebox.runCommand("/playanimation @s animation.hb_cb.mini_jukebox.break");
                mini_jukebox.runCommand("/event entity @s hb_cb:despawn_tick_hit");
              }
              break;
            case "hb_cb:mini_jukebox_despawn":
              const inventoryComponent = mini_jukebox.getComponent("inventory");
              if (!inventoryComponent) return;
              let { container, inventorySize } = inventoryComponent;
              for (let i = 0; i < inventorySize; i++) {
                let foundItem = container.getItem(i);
                if (foundItem) world.getDimension(mini_jukebox.dimension.id).spawnItem(foundItem, mini_jukebox.location);
              }
              mini_jukebox.runCommand("/execute as @a[r=20] run function hb/cb/mj_stop_entity_sounds");
              this.despawnMiniJukebox(mini_jukebox);
              break;
            default:
              break;
          }
        }
      }
    });
  }

  spawnMiniJukebox(player, item) {
    const raycastBlock = player.getBlockFromViewDirection({ includeLiquidBlocks: false, includePassableBlocks: false, maxDistance: 8 });
    if (raycastBlock == undefined) return;
    else {
      let gamemodeCreative = getGamemode(player, 1);
      const location = raycastBlock.block.location;
      const face = raycastBlock.face;

      let placeLoc = getLocationbyFacingBlock(face, location);
      if (checkLocation(placeLoc, player, placeLoc, 0)) return;

      // let mini_jukebox = world.getDimension(player.dimension.id).spawnEntity(item.typeId, placeLoc);
      let yRotation = getEntityRotation(player);

      let block = world.getDimension(player.dimension.id).getBlock({ x: placeLoc.x, y: placeLoc.y, z: placeLoc.z });
      block.setType("hb_cb:mini_jukebox_block");
      player.runCommand("/setblock " + placeLoc.x.toString() + " " + placeLoc.y.toString() + " " + placeLoc.z.toString() + " hb_cb:mini_jukebox_block");
      // player.runCommand("/playsound block.lantern.place @a[r=10] ~~~ 1 1");
      player.runCommand("/summon " + getStringBefore(item.typeId, "_item") + " " + placeLoc.x.toString() + " " + placeLoc.y.toString() + " " + placeLoc.z.toString() + " " + yRotation.toString() + " 0");
      if (!gamemodeCreative) {
        player.runCommand("/clear @s " + item.typeId + " 0 1");
      }
    }
  }

  despawnMiniJukebox(mini_jukebox) {
    mini_jukebox.runCommand("/playanimation @s animation.hb_cb.mini_jukebox.despawn");
    system.waitTicks(1).then(() => {
      if (mini_jukebox.isValid()) {
        if (mini_jukebox.hasTag("hb_cb:start_block_despawn")) {
          try {
            mini_jukebox.teleport({ x: mini_jukebox.location.x, y: mini_jukebox.location.y + 0.5, z: mini_jukebox.location.z });
          } catch (error) {}
        }
      }
      let block = world.getDimension(mini_jukebox.dimension.id).getBlock({ x: mini_jukebox.location.x, y: mini_jukebox.location.y, z: mini_jukebox.location.z });
      block.setType("minecraft:air");
      let spawnedItem = new ItemStack("hb_cb:mini_jukebox_item");
      world.getDimension(mini_jukebox.dimension.id).spawnItem(spawnedItem, mini_jukebox.location);
      mini_jukebox.remove();
    });
  }
}
