import * as mc from "@minecraft/server";
import "./air_vehicles";
import { dnaExtractorInteractEvent, grittyDNAExtractInteractEvent } from "./dnaExtractor";
import { centrifugeScriptEvent } from "./machines/centrifuge";
import { poisonSpray, droprandomDinosaurDNAmber, spawnXPandAmber, triggerDinosaurRoar, meteorEvent, getOrCreateScoreboard } from "./utilities";
import { amberConverterScriptEvent, dnaExtractUseEvent } from "./machines/amberConverter";
import { dinoEggUseEvent, incubatorScriptEvent } from "./machines/incubator";
import { electricGunShootEvent, tranquilizingSniperHitEvent, tranquilizingSniperShootEvent } from "./guns";
import { NAMESPACE } from "./anvilConstants";
import { initSyringe, spawnFullSyringes, syringeManager } from "./syringesManager/syringeManager";
import { damageMorph, morphDeath, morphTick } from "./morphManager/morphManager";
import { playerSpawn } from "./morphManager/morphPlayer";
import { morphActionManager } from "./morphManager/morphActions";
import { backpackPlaceEvent, saveBackpackContainer } from "./backpack/backpackManager";
import { guideBookInteractEvent } from "./guidebook";
import { wikiDinoInteractEvent } from "./wikidino";
import * as electricFence from "./electric_fence";
import * as binoculars from "./binoculars";
import * as stegoSword from "./stego_sword";

const players = mc.world.getAllPlayers().reduce((map, player) => {
  map.set(player.id, player);
  return map;
}, new Map());
const ITEM_USE_ON_COOLDOWN_IN_MS = 5000;
let itemLastUsedOnMap = new Map();
mc.world.beforeEvents.worldInitialize.subscribe((event) => {
  electricFence.registerComponent(event);
});
mc.world.afterEvents.playerSpawn.subscribe((event) => {
  if (event.initialSpawn) {
    players.set(event.player.id, event.player);
    playerSpawn(event);
  }
});
mc.world.afterEvents.playerLeave.subscribe((event) => {
  players.delete(event.playerId);
});
mc.world.afterEvents.entityDie.subscribe((eventData) => {
  const damagingEntity = eventData.damageSource.damagingEntity;
  if (damagingEntity) {
    triggerDinosaurRoar(damagingEntity, eventData.deadEntity);
  }
});
mc.world.afterEvents.itemUse.subscribe((eventData) => {
  guideBookInteractEvent(eventData);
  wikiDinoInteractEvent(eventData);
});
mc.world.afterEvents.itemStartUse.subscribe((eventData) => {
  dnaExtractorInteractEvent(eventData);
  grittyDNAExtractInteractEvent(eventData);
  dnaExtractUseEvent(eventData);
  dinoEggUseEvent(eventData);
  syringeManager(eventData);
  morphActionManager(eventData);
  binoculars.startUsing(eventData);
  stegoSword.startUse(eventData);
});
mc.world.afterEvents.itemStopUse.subscribe((eventData) => {
  binoculars.stopUsing(eventData);
});
mc.world.afterEvents.itemReleaseUse.subscribe((eventData) => {
  electricGunShootEvent(eventData);
  tranquilizingSniperShootEvent(eventData);
});
mc.world.afterEvents.itemCompleteUse.subscribe((eventData) => {
  if (eventData.itemStack.typeId === `${NAMESPACE}:cooked_dino_meat`) {
    eventData.source.addEffect("resistance", 10 * 20, { amplifier: 1 });
    eventData.source.addEffect("strength", 10 * 20, { amplifier: 1 });
  }
});
mc.world.afterEvents.projectileHitEntity.subscribe((eventData) => {
  tranquilizingSniperHitEvent(eventData);
  damageMorph(eventData.getEntityHit().entity);
  spawnXPandAmber(eventData.getEntityHit().entity, eventData.source);
});
mc.world.afterEvents.entityHitEntity.subscribe((eventData) => {
  damageMorph(eventData.hitEntity);
  spawnXPandAmber(eventData.hitEntity, eventData.damagingEntity);
});

mc.world.afterEvents.playerPlaceBlock.subscribe((event) => {
  electricFence.onBlockUpdate(event, false);
});
mc.world.beforeEvents.playerBreakBlock.subscribe((event) => {
  electricFence.onBlockUpdate(event, true);
  droprandomDinosaurDNAmber(event);
});
mc.world.afterEvents.pistonActivate.subscribe((event) => {
  electricFence.onBlockUpdate(event);
});
mc.world.afterEvents.entityHealthChanged.subscribe((eventData) => {
  morphDeath(eventData);
});
mc.world.beforeEvents.itemUseOn.subscribe((eventData) => {
  const itemStack = eventData.itemStack;
  const player = eventData.source;
  const block = eventData.block;
  if (itemStack && itemStack.typeId === `${NAMESPACE}:pteranodon_trophy_spawn_egg`) {
    if (
      eventData.blockFace !== mc.Direction.Down ||
      !(
        eventData.block.below(1)?.permutation.matches("minecraft:air") &&
        eventData.block.below(2)?.permutation.matches("minecraft:air") &&
        eventData.block.below(3)?.permutation.matches("minecraft:air") &&
        eventData.block.below(4)?.permutation.matches("minecraft:air")
      )
    ) {
      eventData.cancel = true;
      player.runCommandAsync(`titleraw @s actionbar ${JSON.stringify({ rawtext: [{ translate: `${NAMESPACE}.pteranodon_trophy_error` }] })}`);
    }
  }
  if (itemStack && itemStack.typeId === "minecraft:brush" && block.typeId === "minecraft:suspicious_gravel" && block.permutation.getState("brushed_progress") <= 1) {
    let id = player.id;
    let currentTime = Date.now();
    let lastTime = itemLastUsedOnMap.get(id);
    itemLastUsedOnMap.set(id, currentTime);
    if (lastTime && currentTime - lastTime < ITEM_USE_ON_COOLDOWN_IN_MS) return;
    if (Math.random() <= 0.3) {
      player.runCommandAsync(`/structure load ${NAMESPACE}:suspicious_gravel ${block.location.x} ${block.location.y} ${block.location.z}`);
    }
  }
  if (itemStack && itemStack.typeId === "minecraft:brush" && block.typeId === "minecraft:suspicious_sand" && block.permutation.getState("brushed_progress") <= 1) {
    let id = player.id;
    let currentTime = Date.now();
    let lastTime = itemLastUsedOnMap.get(id);
    itemLastUsedOnMap.set(id, currentTime);
    if (lastTime && currentTime - lastTime < ITEM_USE_ON_COOLDOWN_IN_MS) return;
    if (Math.random() <= 0.3) {
      player.runCommandAsync(`/structure load ${NAMESPACE}:suspicious_sand ${block.location.x} ${block.location.y} ${block.location.z}`);
    }
  }
});
mc.world.afterEvents.itemUseOn.subscribe((eventData) => {
  backpackPlaceEvent(eventData);
});
mc.system.afterEvents.scriptEventReceive.subscribe((eventData) => {
  centrifugeScriptEvent(eventData);
  amberConverterScriptEvent(eventData);
  incubatorScriptEvent(eventData);
  spawnFullSyringes(eventData);
  poisonSpray(eventData);
});
mc.system.afterEvents.scriptEventReceive.subscribe((data) => {
  saveBackpackContainer(data);
});
["gamerule showtags false", "gamerule sendcommandfeedback false"].forEach((command) => {
  mc.world.getDimension(mc.MinecraftDimensionTypes.overworld).runCommand(command);
});
mc.system.runInterval(() => {
  for (const player of players.values()) {
    initSyringe(player);
    morphTick(player);
  }
  for (const player of mc.world.getAllPlayers()) {
    const { x: vx, y: vy, z: vz } = player.getVelocity();
    const speed = Math.hypot(vx, vy, vz);
    const kmph = speed * 20 * 3.6;
    const mph = kmph * 0.621371;
    if (!player.getComponent("minecraft:riding") && player.hasTag(`${NAMESPACE}:is_in_vehicle`)) {
    	player.runCommandAsync(`/camera @s clear`);
        player.removeTag(`${NAMESPACE}:is_in_vehicle`);
        mc.system.runTimeout(() => {
        if (player.isValid()) {
            player.camera.clear();
        }
    }, 5);
    }
    if (player.hasTag(`${NAMESPACE}:is_in_vehicle`) && player.getComponent("minecraft:riding")) {
      player.onScreenDisplay.setActionBar({
        rawtext: [`${NAMESPACE}.speed`, " ", `${Math.trunc(mph)}`, " ", `${NAMESPACE}.mph`].map((translate) => ({ translate })),
      });
    }
  }
  for (const player of mc.world.getPlayers()) {
    const inventory = player.getComponent("inventory");
    const { container, inventorySize } = inventory;
    const heldItem = container.getItem(player.selectedSlotIndex);
    for (let i = 0; i < inventorySize; i++) {
      const item = container.getItem(i);
      if (!item) continue;
      if (
        (item.typeId === `${NAMESPACE}:dinos_guide2` ||
          item.typeId === `${NAMESPACE}:dinos_guide3` ||
          item.typeId === `${NAMESPACE}:wikidino_book2` ||
          item.typeId === `${NAMESPACE}:wikidino_book3` ||
          item.typeId === `${NAMESPACE}:wikidino_book4` ||
          item.typeId === `${NAMESPACE}:wikidino_book5`) &&
        (heldItem?.typeId !== item.typeId || i !== player.selectedSlotIndex)
      ) {
        if (item.typeId.startsWith(`${NAMESPACE}:dinos_guide`)) {
          container.setItem(i, new mc.ItemStack(`${NAMESPACE}:dinos_guide`, 1));
        } else if (item.typeId.startsWith(`${NAMESPACE}:wikidino_book`)) {
          container.setItem(i, new mc.ItemStack(`${NAMESPACE}:wikidino_book`, 1));
        }
      }
    }
  }
  binoculars.tick1();
  electricFence.tick1();
});
mc.system.runInterval(() => {
  const settingsScoreboard = getOrCreateScoreboard(`${NAMESPACE}.settings`);
  const fall = settingsScoreboard.getScore("meteorite_fall") === 1;
  if (fall) {
    const tick = mc.system.currentTick;
    const interval = 15;
    const duration = 3;
    const intervalTick = interval * 60 * 20;
    const durationTick = duration * 60 * 20;
    if (tick % intervalTick >= 0 && tick % intervalTick <= durationTick) {
      meteorEvent();
    }
  }
}, Math.random() * 5 * 20);
function formatDimension(string) {
  return string
    .split("_")
    .map((w) => w.charAt(0).toUpperCase() + w.slice(1))
    .join(" ");
}
mc.world.afterEvents.entityDie.subscribe(({ deadEntity: entity }) => {
  if (entity instanceof mc.Player) {
    const x = Math.trunc(entity.location.x);
    const y = Math.trunc(entity.location.y);
    const z = Math.trunc(entity.location.z);
    const dimensionString = formatDimension(entity.dimension.id.replace("minecraft:", "")) ?? "§7Unknown Dimension§r";
    entity.sendMessage({
      rawtext: [`${NAMESPACE}.you_died_at`, " ", `${x}, ${y}, ${z}`, " ", `${NAMESPACE}.in`, " ", `${dimensionString}`].map((translate) => ({ translate })),
    });
  }
});
mc.world.beforeEvents.playerInteractWithBlock.subscribe((eventData) => {
  electricFence.triggerToggle(eventData);
});
