import { world, system, Player, EntityDamageCause, BlockVolume, Dimension, Block, BlockComponentRegistry } from "@minecraft/server";
import { displayMainScreen } from "./terminal";
import { MAPS } from "./data";


let OVERWORLD
const SOUND_OPTIONS = { volume: 1, pitch: 1 };

export function damagePlayer(player, damage, sourceEntity, cause) {
  let damageDealt = damage;

  const health = player.getComponent("health");

  if (health.currentValue - damageDealt <= 0 && !player.criticallyInjured && damageDealt < 50) {
    damageDealt = health.currentValue - 5;
  }
  if (health.currentValue - damageDealt <= 0 && damageDealt > 50 && cause == EntityDamageCause.fallingBlock) {
    OVERWORLD.playSound("player.fall.death", player.location, SOUND_OPTIONS);
  } else if (health.currentValue - damageDealt <= 0 && sourceEntity.typeId == "js:hygrodere") {
    OVERWORLD.playSound("monster.hygrodere.kill_player", player.location, SOUND_OPTIONS);
  } else if (health.currentValue - damageDealt <= 0 && sourceEntity.typeId == "js:coil_head") {
    OVERWORLD.playSound("monster.coil_head.kill_player", player.location, SOUND_OPTIONS);
  } else {
    OVERWORLD.playSound("items.shovel.hit_player", player.location, SOUND_OPTIONS);
  }

  if (health.currentValue - damageDealt <= 0) {
    if (sourceEntity && sourceEntity.typeId == "js:company") {
      player.causeOfDeath = "company";
    } else if (sourceEntity && sourceEntity.typeId == "js:forest_keeper") {
      player.causeOfDeath = "giant";
    }  else if (sourceEntity && sourceEntity.typeId == "js:earth_leviathan") {
      player.causeOfDeath = "worm";
    } else {
      player.causeOfDeath = cause;
    }
  }

  player.runCommand(`camerashake add @s 0.3 0.2 rotational`);
  if (sourceEntity !== null) {
    player.applyDamage(damageDealt, {
      cause: cause,
      damagingEntity: sourceEntity,
    });
  } else {
    player.applyDamage(damageDealt, {
      cause: cause,
    });
  }

  console.warn(`${player.nameTag} received ${damage} damage  cause ${cause}`);
}



/**
 * @param {Block} block
 */
function mineExplode(block) {
  const dimension = block.dimension;
  const location = block.location;
  
  block.setPermutation(block.permutation.withState("js:activated", true));
  block.setPermutation(block.permutation.withState("js:stepped_on", true));

  dimension.playSound("misc.mine.trigger", location, SOUND_OPTIONS);
  dimension.spawnParticle("ding:flash", { x: location.x + 0.5, y: location.y + 0.25, z: location.z + 0.5 });

  system.runTimeout(() => {
    dimension.playSound("misc.mine.detonate", location, SOUND_OPTIONS);
    dimension.spawnParticle("ding:landmine_impact", location);
    dimension.spawnParticle("ding:landmine_flames", location);

    const mineEntity = dimension.getEntities({ location: location, type: "js:mine", maxDistance: 1, closest: 1 });
    mineEntity.forEach((entity) => {
      entity.remove();
    });

    const dead = dimension.getEntities({ location: location, type: "minecraft:player", maxDistance: 5 });
    const injured = dimension.getEntities({
      location: location,
      type: "minecraft:player",
      minDistance: 5,
      maxDistance: 9.1,
    });

    for (let player of dead) {
      damagePlayer(player, 100, null, EntityDamageCause.blockExplosion);
    }
    for (let player of injured) {
      damagePlayer(player, 50, null, EntityDamageCause.blockExplosion);
    }

    const entityKill = dimension.getEntities({ location: location, families: ["monster"], maxDistance: 5 });

    for (let entity of entityKill) {
      if (entity.typeId == "js:hygrodere" || entity.typeId == "js:coil_head") continue;

      entity.applyDamage(50, {
        cause: EntityDamageCause.blockExplosion,
      });
    }

    const volume = new BlockVolume(
      { x: location.x - 5, y: location.y - 5, z: location.z - 5 },
      { x: location.x + 5, y: location.y + 5, z: location.z + 5 }
    );

    dimension.setBlockType(location, "minecraft:air");
    
    const locations = dimension.getBlocks(volume, { includeTypes: ["js:mine"] }, false);

    for (const location of locations.getBlockLocationIterator()) {
      const block = dimension.getBlock(location);
      if (block && block.permutation.getState("js:stepped_on") == false) {
        mineExplode(block);
      }
    }

  }, 15);
}


const FLOOR_GRATE_CONNECTING_BLOCKS = ["ding:floor_grate"];
const MANSION_BOOKSHELF_CONNECTING_BLOCKS = ["ding:mansion_bookshelf"];

system.beforeEvents.startup.subscribe(({blockComponentRegistry}) => {
  blockComponentRegistry.registerCustomComponent('kai:on_player_destroy', {
      onPlayerDestroy(e) {
          // Destructure event data for easier access
          const { player, dimension } = e;

          // Extract destroyed block permutation from event data
          const { destroyedBlockPermutation: perm } = e;

          // Check if player and equipment are valid
          if (!player || !player.getComponent('equippable')) {
              return;
          }

          // Get the item in the player's main hand
          const selectedItem = player.getComponent('equippable').getEquipment('Mainhand');

          // Check if the selected item is a pickaxe
          if (!selectedItem || !selectedItem.hasTag('minecraft:is_pickaxe')) {
              return;
          }

          // Use destroyedBlockPermutation to get the ItemStack directly
          const slabItem = perm.getItemStack(1);
          if (slabItem) {
              // Spawn the item at the destroyed block location
              dimension.spawnItem(slabItem, e.block.location);
          }
      }
  });
  blockComponentRegistry.registerCustomComponent("js:mine_step", {
    onStepOff(e) {
      const { entity, block, dimension } = e;
      if (!entity) return;

      const steppedOn = block.permutation.getState("js:stepped_on");
      const activated = block.permutation.getState("js:activated");
      if (entity.typeId == "minecraft:player" && steppedOn == false && activated == false) {
        block.setPermutation(block.permutation.withState("js:stepped_on", true));
        dimension.playSound("misc.mine.trigger", block.location, SOUND_OPTIONS);
        dimension.spawnParticle("ding:flash", {
          x: block.location.x + 0.5,
          y: block.location.y + 0.25,
          z: block.location.z + 0.5,
        });

        system.runTimeout(() => {
          dimension.playSound("misc.mine.detonate", block.location, SOUND_OPTIONS);
          dimension.spawnParticle("ding:landmine_impact", block.location);
          dimension.spawnParticle("ding:landmine_flames", block.location);

          const mineEntity = dimension.getEntities({
            location: block.location,
            type: "js:mine",
            maxDistance: 1,
            closest: 1,
          });
          mineEntity.forEach((entity) => {
            entity.remove();
          });

          const dead = dimension.getEntities({ location: block.location, type: "minecraft:player", maxDistance: 5 });
          const injured = dimension.getEntities({
            location: block.location,
            type: "minecraft:player",
            minDistance: 5,
            maxDistance: 9.1,
          });

          for (let player of dead) {
            damagePlayer(player, 100, null, EntityDamageCause.blockExplosion);
          }
          for (let player of injured) {
            damagePlayer(player, 50, null, EntityDamageCause.blockExplosion);
          }

          const entityKill = dimension.getEntities({ location: block.location, families: ["monster"], maxDistance: 5 });

          for (let entity of entityKill) {
            if (entity.typeId == "js:hygrodere" || entity.typeId == "js:coil_head") continue;

            entity.applyDamage(50, {
              cause: EntityDamageCause.blockExplosion,
            });
          }

          const volume = new BlockVolume(
            { x: block.location.x - 5, y: block.location.y - 5, z: block.location.z - 5 },
            { x: block.location.x + 5, y: block.location.y + 5, z: block.location.z + 5 }
          );

          const locations = dimension.getBlocks(volume, { includeTypes: ["js:mine"] }, false);

          for (const location of locations.getBlockLocationIterator()) {
            const block = dimension.getBlock(location);
            if (block && block.permutation.getState("js:stepped_on") == false) {
              mineExplode(block);
            }
          }

          dimension.setBlockType(block.location, "minecraft:air");
        }, 15);
      }
    },
    onTick(e) {
      const { block, dimension } = e;

      if (block.typeId == "js:mine") {
        dimension.playSound("misc.mine.beep", block.location, SOUND_OPTIONS);
        dimension.spawnParticle("ding:flash", {
          x: block.location.x + 0.5,
          y: block.location.y + 0.25,
          z: block.location.z + 0.5,
        });
      }
    },
  });


  blockComponentRegistry.registerCustomComponent("js:door_buttons_block", {
    onTick(e) {
      const { block } = e;
      block.setPermutation(block.permutation.withState("ding:cooldown", 0));
    },
  });

  blockComponentRegistry.registerCustomComponent("js:delete", {
    onTick(e) {
      const { block, dimension } = e;
      dimension.runCommand(`setblock ${block.x} ${block.y} ${block.z} air`);
    },
  });

  blockComponentRegistry.registerCustomComponent("js:gap_block", {
    onStepOn(e) {
      const { entity, block } = e;
      if (entity instanceof Player) {
        block.setPermutation(block.permutation.withState("js:player_step", true));
      }
    },
    onEntityFallOn(e) {
      const { entity, block } = e;
      if (entity instanceof Player) {
        block.setPermutation(block.permutation.withState("js:player_step", true));
      }
    },
    onTick(e) {
      const { block, dimension } = e;
      block.setPermutation(block.permutation.withState("js:player_step", false));
    },
    onStepOff(e) {
      const { entity, block } = e;
      block.setPermutation(block.permutation.withState("js:player_step", false));
    },
  })

  blockComponentRegistry.registerCustomComponent("js:death_block", {
    onStepOn(e) {
      const { entity } = e;
      if (entity instanceof Player) {
        damagePlayer(entity, 100, null, EntityDamageCause.fallingBlock);
      }

      const familyComponent = entity.getComponent('minecraft:type_family')
      if (familyComponent && familyComponent.hasTypeFamily('monster')) {
        const moonId = world.getDynamicProperty("moon");
        let shipLocation;
        for (const key of Object.keys(MAPS)) {
          if (MAPS[key].id === moonId) {
            shipLocation = MAPS[key].shipLocation;
            break;
          }
        }
      
        let teleportLocation = {
          x: shipLocation.x + 3.99,
          y: shipLocation.y - 60 - 30,
          z: shipLocation.z + 1.8,
        };

        if (world.getDynamicProperty('facilityType') == "mansion") {
          teleportLocation = {
            x: shipLocation.x + 12.0,
            y: shipLocation.y - 74 - 30,
            z: shipLocation.z + 1.5,
          };
        }
        entity.teleport(teleportLocation)
      }
    },
    onStepOff(e) {
      const { entity } = e;
      if (entity instanceof Player) {
        damagePlayer(entity, 100, null, EntityDamageCause.fallingBlock);
      }
      const familyComponent = entity.getComponent('minecraft:type_family')
      if (familyComponent && familyComponent.hasTypeFamily('monster')) {
        const moonId = world.getDynamicProperty("moon");
        let shipLocation;
        for (const key of Object.keys(MAPS)) {
          if (MAPS[key].id === moonId) {
            shipLocation = MAPS[key].shipLocation;
            break;
          }
        }
        let teleportLocation = {
          x: shipLocation.x + 3.99,
          y: shipLocation.y - 60 - 30,
          z: shipLocation.z + 1.8,
        };
        entity.teleport(teleportLocation)
      }
    },
    onEntityFallOn(e) {
      const { entity } = e;
      if (entity instanceof Player) {
        damagePlayer(entity, 100, null, EntityDamageCause.fallingBlock);
      }
      const familyComponent = entity.getComponent('minecraft:type_family')
      if (familyComponent && familyComponent.hasTypeFamily('monster')) {
        const moonId = world.getDynamicProperty("moon");
        let shipLocation;
        for (const key of Object.keys(MAPS)) {
          if (MAPS[key].id === moonId) {
            shipLocation = MAPS[key].shipLocation;
            break;
          }
        }
        let teleportLocation = {
          x: shipLocation.x + 3.99,
          y: shipLocation.y - 60 - 30,
          z: shipLocation.z + 1.8,
        };
        entity.teleport(teleportLocation)
      }
    },
  });

  blockComponentRegistry.registerCustomComponent("js:tick", {
    onTick(e) {
      const { block, dimension } = e;
      const onState = block.permutation.getState('js:on')
      if (block.typeId == "ding:candle") {
        dimension.spawnParticle("ding:small_flame", {
          x: block.x + 0.5,
          y: block.y + 0.6,
          z: block.z + 0.5,
        });
      }

      if (block.typeId == "ding:wall_lantern" && onState == true) {
        dimension.spawnParticle("ding:bloom3", {
          x: block.x + 0.5,
          y: block.y + 0.5,
          z: block.z + 0.5,
        });
      }

      if (block.typeId == "ding:ceiling_lamp" && onState == true) {
        dimension.spawnParticle("ding:bloom", {
          x: block.x + 0.5,
          y: block.y + 0.25,
          z: block.z + 0.5,
        });
        dimension.spawnParticle("ding:bloom2", {
          x: block.x + 0.5,
          y: block.y + 0.25,
          z: block.z + 0.5,
        });
        dimension.spawnParticle("ding:light_ray", {
          x: block.x + 0.5,
          y: block.y - 0.3125,
          z: block.z + 0.5,
        });
      }

      if (block.typeId == "ding:fire_exit_lamp") {
        dimension.spawnParticle("ding:fire_exit_shine", {
          x: block.x + 0.5,
          y: block.y - 0.5,
          z: block.z + 0.5,
        });
      }
      if (block.typeId == "ding:wall_lamp" && onState == true) {
        dimension.spawnParticle("ding:lamp_shine", {
          x: block.x + 0.5,
          y: block.y - 0.5,
          z: block.z + 0.5,
        });
      }
      if (block.typeId == "ding:light_pole_lantern") {
        dimension.spawnParticle("ding:light_post", {
          x: block.x + 0.5,
          y: block.y - 0.2,
          z: block.z + 0.5,
        });
      }

      if (block.typeId == "ding:floor_grate") {
        floorGrate(block);
      }

      if (block.typeId == "ding:mansion_bookshelf") {
        mansionBookshelf(block);
      }

      if (
        block.typeId == "js:facility_door" ||
        block.typeId == "js:fire_exit_door" ||
        block.typeId == "js:main_door" ||
        block.typeId == "ding:terminal_block" ||
        block.typeId == "ding:ship_charger"
      ) {
        block.setPermutation(block.permutation.withState("js:cooldown", false));
      }

      if (block.typeId == "js:sound_marker") {
        dimension.setBlockType(block, "minecraft:air");
      }
    },
    onPlace(e) {
      const { block } = e;
      if (block.typeId == "ding:floor_grate") {
        floorGrate(block);
      }
    },
  });

  blockComponentRegistry.registerCustomComponent("js:water_puddle", {
    onPlace(e) {
      const { block } = e;
    
      const random = Math.random();
      const random2 = Math.floor(Math.random() * 6);
      block.setPermutation(block.permutation.withState("js:rotation", random2));
    
      let value;
      if (random < 0.25) {
        value = 0;
      } else if (random >= 0.25 && random < 0.5) {
        value = 1;
      } else if (random >= 0.5 && random < 0.75) {
        value = 2;
      } else {
        value = 3;
      }
    
      block.setPermutation(block.permutation.withState("js:type", value));
    },
    
  });
  blockComponentRegistry.registerCustomComponent("js:wooden_panels", {
    onPlace(e) {
      const { block } = e;
      const random = Math.floor(Math.random() * 4);
      block.setPermutation(block.permutation.withState("js:type", random));
    },
  });
  blockComponentRegistry.registerCustomComponent("js:march_grass", {
    onPlace(e) {
      const { block } = e;
      const random = Math.floor(Math.random() * 3);
      block.setPermutation(block.permutation.withState("js:type", random));
    },
  });

  blockComponentRegistry.registerCustomComponent("js:ship_speaker", {
    onPlayerInteract(e) {
      const { block, player } = e;
      if (!player) return;
      
      player.runCommand(`stopsound @a game.profit.intro`);
      player.runCommand(`stopsound @a game.profit.zero_days_left`);
      player.playSound('buttons.ship.speaker_cut')
    },
  });

  blockComponentRegistry.registerCustomComponent("js:terminal", {
    onPlace(e) {
      const { block } = e;
      if (block.typeId == "ding:terminal_block") {
        block.setPermutation(block.permutation.withState("js:cooldown", false));
      }
    },
    onPlayerInteract(e) {
      const { block, player } = e;
      if (!player) return;
      if (block.typeId !== "ding:terminal_block") return;
      block.setPermutation(block.permutation.withState("js:cooldown", true));

      console.warn(`eee`)
      let terminalLocation = block;
      displayMainScreen(player);
      player.setProperty("js:player_animation", 1);
      player.teleport(
        { x: terminalLocation.x - 0.5, y: terminalLocation.y - 1, z: terminalLocation.z + 0.5 },
        { rotation: { x: 0, y: -90 } }
      );
    },
  });

  blockComponentRegistry.registerCustomComponent("js:electrical_box", {
    onPlayerInteract(e) {
      const { block, player } = e;
      if (!player) return;
      if (block.typeId !== "ding:electrical_box") return;
      const state = block.permutation.getState('js:open')
      
      if (state == true) {
        block.setPermutation(block.permutation.withState("js:open", false));
        OVERWORLD.playSound('door.breaker_box.close', block.location)
      } else {
        block.setPermutation(block.permutation.withState("js:open", true));
        OVERWORLD.playSound('door.breaker_box.open', block.location)
      }

    },
  });
});


function floorGrate(block) {
  const location = block;
  const north = { x: location.x, y: location.y, z: location.z - 1 };
  const south = { x: location.x, y: location.y, z: location.z + 1 };
  const east = { x: location.x - 1, y: location.y, z: location.z };
  const west = { x: location.x + 1, y: location.y, z: location.z };

  const dimension = block.dimension;

  const northBlock = dimension.getBlock(north);
  const southBlock = dimension.getBlock(south);
  const eastBlock = dimension.getBlock(east);
  const westBlock = dimension.getBlock(west);
  const perm = block.permutation
    .withState("ding:north", northBlock && FLOOR_GRATE_CONNECTING_BLOCKS.includes(northBlock.typeId) ? 1 : 0)
    .withState("ding:south", southBlock && FLOOR_GRATE_CONNECTING_BLOCKS.includes(southBlock.typeId) ? 1 : 0)
    .withState("ding:east", eastBlock && FLOOR_GRATE_CONNECTING_BLOCKS.includes(eastBlock.typeId) ? 1 : 0)
    .withState("ding:west", westBlock && FLOOR_GRATE_CONNECTING_BLOCKS.includes(westBlock.typeId) ? 1 : 0);

  block.setPermutation(perm);
}




function mansionBookshelf(block) {
  const location = block;
  const up = { x: location.x, y: location.y+1, z: location.z };
  const north = { x: location.x, y: location.y, z: location.z - 1 };
  const south = { x: location.x, y: location.y, z: location.z + 1 };
  const east = { x: location.x - 1, y: location.y, z: location.z };
  const west = { x: location.x + 1, y: location.y, z: location.z };

  const dimension = block.dimension;
  const topBlock = dimension.getBlock(up);
  const northBlock = dimension.getBlock(north);
  const southBlock = dimension.getBlock(south);
  const eastBlock = dimension.getBlock(east);
  const westBlock = dimension.getBlock(west);

  const rng = Math.round(Math.random()*2)

  const perm = block.permutation
    .withState("ding:variant", rng)
    .withState("ding:top", topBlock && MANSION_BOOKSHELF_CONNECTING_BLOCKS.includes(topBlock.typeId) ? 1 : 0)
    .withState("ding:north", northBlock && MANSION_BOOKSHELF_CONNECTING_BLOCKS.includes(northBlock.typeId) ? 1 : 0)
    .withState("ding:south", southBlock && MANSION_BOOKSHELF_CONNECTING_BLOCKS.includes(southBlock.typeId) ? 1 : 0)
    .withState("ding:east", eastBlock && MANSION_BOOKSHELF_CONNECTING_BLOCKS.includes(eastBlock.typeId) ? 1 : 0)
    .withState("ding:west", westBlock && MANSION_BOOKSHELF_CONNECTING_BLOCKS.includes(westBlock.typeId) ? 1 : 0);

  block.setPermutation(perm);
}



world.afterEvents.worldLoad.subscribe(() => {
  OVERWORLD = world.getDimension("overworld");
  import("./main.js")
})
