import { EquipmentSlot, system, world, MolangVariableMap, ItemStack,Difficulty, GameMode } from "@minecraft/server";
import { Attack } from "./items/spears.js"
import { artifacts, artifactsWork20T, artifactsWork40T, BewitchedFirework } from "./items/artifacts/artifacts.js"
import { equipmentWork } from "./items/armors/armors_effects.js"
import { deceitwebArmorEatAndGrow, deceitwebArmorEffects } from "./items/armors/deceitweb.js"
import { brushItemOut, brush } from "./blocks/archeology_things.js";
import { fakeEvents } from "./fake_events.js";
import { NetherRoofTeleport, EndTpPlatform, OverworldTp } from "./utils/teleport.js"
import { getScore, TimerScoreboard5Ticks } from "./utils/score.js";
import { BondlingLine, OculusLaser } from "./entity/runic_mobs.js";


const armorSlots = [EquipmentSlot.Head, EquipmentSlot.Chest, EquipmentSlot.Legs, EquipmentSlot.Feet];




//-----------------------------------------
//Ticking
//-----------------------------------------

system.beforeEvents.startup.subscribe(eventData => {
  //chaque tick
  system.runInterval(() => {

    EachTick()


  }
  )
  //2 ticks
  system.runInterval(() => {

    Each2Ticks()


  }, 2
  )
  //4 par seconde
  system.runInterval(() => {
    Each5Ticks()

  }, 5)

  //chaque seconde
  system.runInterval(() => {
    EachSecond()

  }, 20)


  //chaque 2 secondes
  system.runInterval(() => {
    system.runJob(Each2Seconds())

  }, 40
  )

  //chaque minute
  system.runInterval(() => {
    system.runJob(deceitwebArmorEatAndGrow())
  }, 1200)
})

function EachTick() {
  for (const player of world.getPlayers()) {
    fakeEvents(player)
    CameraShake(player)
    HitCooldown(player)
    FireBreath(player)
    BloodMoonSleep(player)
    if (player.hasTag('attack')) {
      player.removeTag('attack')
      Attack(player)
    }

  }
}
function Each2Ticks() {
  OculusLaser()
}
function Each5Ticks() {
  brushItemOut()
  const dimensions = ['overworld', 'nether', 'the_end'].map(dim => world.getDimension(dim))
  for (const dim of dimensions) {
    BewitchedFirework(dim)
    const potions = dim.getEntities({ type: 'edx:area_incendiary_potion' });
    for (const potion of potions) {
      let entities = dim.getEntities({ location: { x: potion.location.x - 3, y: potion.location.y, z: potion.location.z - 3 }, volume: { x: 6, y: 1, z: 6 } });
      for (const entity of entities) {
        entity.setOnFire(10);
      }
    }
  }
  for (const player of world.getPlayers()) {
    TimerScoreboard5Ticks(player)
  }
}
function EachSecond() {
  
  BondlingLine()
  bloodMoon()
  const dimensions = ['overworld', 'nether', 'the_end'].map(dim => world.getDimension(dim))
  for (const dim of dimensions) {
    StrangeTotem(dim)
    bleedingEffect(dim)
  }
  for (const player of world.getPlayers()) {
    //try{

    EndTpPlatform(player)
    OverworldTp(player)
    NetherRoofTeleport(player)
    equipmentWork(player)
    artifactsWork20T(player)
    brush(player)
    deceitwebLiver(player)
    UpdateSpeed(player)
    ShieldBlock(player)
    NoPortal(player)
    ChargingParticle(player)
    //} catch(e){}
  }
}
function* Each2Seconds() {
  const players = world.getPlayers()
  for (let i = 0; i < players.length; i++) {
    yield
    let player = players[i]
    //try{
    artifacts(player)
    yield
    artifactsWork40T(player)
    yield
    deceitwebArmorEffects(player)
    UpdateHearts(player)
    yield
    LightVoidArmor(player)
    HardAndVoidMode(player)
    yield
    FogAndParticle(player)
    //} catch(e){}
  }
}

//-----------------------------------------
//fonctions
//-----------------------------------------



function bleedingEffect(dimension) {
  const entities = dimension.getEntities({ excludeFamilies: ["projectile", "inanimate"] });
  for (const entity of entities) {
    if (entity.hasTag("bleeding1")) {
      entity.removeTag("bleeding1");
      entity.runCommand(`damage @s 1 none`)
      entity.runCommand(`particle edx:blood ~~~`);
    }
    if (entity.hasTag("bleeding2")) {
      entity.removeTag("bleeding2");
      entity.runCommand(`tag @s add bleeding1`);
      entity.runCommand(`damage @s 1 none`)
      entity.runCommand(`particle edx:blood ~~~`);
    }
    if (entity.hasTag("bleeding3")) {
      entity.removeTag("bleeding3");
      entity.runCommand(`tag @s add bleeding2`);
      entity.runCommand(`damage @s 1 none`)
      entity.runCommand(`particle edx:blood ~~~`);
    }
    if (entity.hasTag("bleeding4")) {
      entity.removeTag("bleeding4");
      entity.runCommand(`tag @s add bleeding3`);
      entity.runCommand(`damage @s 2 none`)
      entity.runCommand(`particle edx:blood ~~~`);
    }
    if (entity.hasTag("bleeding")) {
      entity.removeTag("bleeding");
      entity.runCommand(`tag @s add bleeding4`);
      entity.runCommand(`damage @s 2 none`)
      entity.runCommand(`particle edx:blood ~~~`);
    }
  }
}




function deceitwebLiver(player) {
  if (player.hasTag("Liver_break")) {
    player.dimension.spawnParticle('edx:deceitweb_liver_player_particle', player.location);
  }
}



function bloodMoon() {
  const blood_moon = (((world.getAbsoluteTime() - world.getTimeOfDay()) / 24000) + 2) % 8 == 0;
  const night_time = world.getTimeOfDay() > 12000 && world.getTimeOfDay() < 24000;
  if (blood_moon && night_time) {
    world.setDynamicProperty('blood_moon', true)
  }
  else if (!blood_moon || !night_time) {
    world.setDynamicProperty('blood_moon', false)
  }
  for (const player of world.getPlayers()) {
    if (blood_moon && night_time && player.dimension.id == "minecraft:overworld") {
      player.dimension.setWeather('Clear')
      player.addTag('blood_moon');
      player.spawnParticle('edx:blood_rain', player.location);
    }
    else if (!blood_moon || !night_time) {
      player.removeTag('blood_moon');
    }
    if (player.hasTag('blood_moon') && !player.hasTag('already_blood_moon') && player.dimension.id == "minecraft:overworld") {
      player.runCommand('fog @s push edx:blood_moon_fog blood_moon')
      var bloodMessage = {
        rawtext: [{
          translate: "message.event.blood_moon",
        }]
      };
      player.sendMessage(bloodMessage)
      player.playSound('random.click');
      player.addTag('already_blood_moon')
    }
    if (!player.hasTag('blood_moon') && player.hasTag('already_blood_moon')) {
      player.removeTag('already_blood_moon')
      player.runCommand('fog @s remove blood_moon')
    }
  }
}

function UpdateHearts(player) {
  const scoreboard = world.scoreboard.getObjective("max_health");
  const score = scoreboard.getScore(player)
  if (1 <= score && score <= 60) {
    player.triggerEvent("health_" + score.toString())
  }
  else if (score == 0) {
    player.triggerEvent("health_20")
    scoreboard.setScore(player, 20)
  }
}

function UpdateSpeed(player) {
  const scoreboard = world.scoreboard.getObjective("speed");
  const score = scoreboard.getScore(player)
  if (-3 <= score <= 7) {
    player.triggerEvent("speed" + score.toString())
  }
}
function LightVoidArmor(player) {
  const score = world.scoreboard.getObjective('max_health');
  const equipment = player.getComponent('equippable');
  var lightV = 0
  var voidV = 0
  for (const slot of armorSlots) {
    const item = equipment.getEquipment(slot);
    if (item?.getTags().includes("light_armor")) lightV += 1;
    else if (item?.getTags().includes("void_armor")) voidV += 1;
    else break;
  }
  if (lightV == 4 && !player.hasTag('already_light_hearts')) {
    player.addTag('already_light_hearts')
    score.addScore(player, 2)
  }
  else if (lightV != 4 && player.hasTag('already_light_hearts')) {
    player.removeTag('already_light_hearts')
    score.addScore(player, -2)
  }
  if (voidV == 4) {
    player.addTag('void_armor')
  }
  else if (voidV != 4) {
    player.removeTag('void_armor')
  }
  if ((lightV == 4 && equipment?.getEquipment('Mainhand')?.getTags().includes('edx:void')) && (voidV == 4 && equipment?.getEquipment('Mainhand')?.getTags().includes('edx:light'))) {
    player.addEffect('weakness', 4, { amplifier: 5, showParticles: false })
  }
}

function HardAndVoidMode(player) {
  const hardMode = world?.getDynamicProperty('hard_mode')
  const diff = world.scoreboard.getObjective('difficulty');
  if (hardMode == true) {
    if (diff?.getScore(player) == undefined || diff?.getScore(player) == 0) {
      diff.setScore(player, 1)
    }
  }
  const voidMode = world?.getDynamicProperty('void_mode')
  const diff2 = world.scoreboard.getObjective('difficulty2');
  if (voidMode == true) {
    if (diff2?.getScore(player) == undefined || diff2?.getScore(player) == 0) {
      diff2.setScore(player, 1)
    }
  }
  
  if (diff?.getScore(player) == 1) {
    var HardModeMessage = {
      rawtext: [{
        translate: "message.event.HardMode",
      }]
    };
    player.sendMessage(HardModeMessage)
    diff?.setScore(player, 2)
  }
  if (diff2?.getScore(player) == 1) {
    var VoidModeMessage = {
      rawtext: [{
        translate: "message.event.VoidMode",
      }]
    };
    player.sendMessage(VoidModeMessage)
    diff2?.setScore(player, 2)
  }

  
  
  if (voidMode == false && diff?.getScore(player) == 2) {
    diff2.setScore(player, 0)
    var VoidModeMessageReset = {
      rawtext: [{
        translate: "message.event.HardModeReset",
      }]
    };
    player.sendMessage(VoidModeMessageReset)
  }
  else if(hardMode == false && diff?.getScore(player) == 2) {
    diff2.setScore(player, 0)
    diff.setScore(player, 0)
    var HardModeMessageReset = {
      rawtext: [{
        translate: "message.event.NormalModeReset",
      }]
    };
    player.sendMessage(HardModeMessageReset)
  }
}

function NoPortal(player) {
  //last time i'm patching this bug, now i'll remove the whole portal bc fuck you!!
  if (!player.hasTag('abom') && !player.matches({ gameMode: GameMode.Creative })) {
    const block = player.dimension.getBlock(player.location)
    const blocks = [block, block.north(), block.south(), block.east(), block.west()]

    for (var b of blocks) {
      if (b.typeId == "minecraft:portal") {

        var PortalMessage = {
          rawtext: [{
            translate: "message.event.Portal",
          }]
        };
        b.setType('minecraft:air')
        player.sendMessage(PortalMessage)
        var obsi = b.dimension.getBlockFromRay(b.center(), { x: 0, y: -1, z: 0 }, { maxDistance: 50, includePassableBlocks: false, includeTypes: ["minecraft:obsidian"] })?.block
        if (obsi.typeId == 'minecraft:obsidian')
          obsi.dimension.runCommand(`setblock ${obsi.location.x} ${obsi.location.y} ${obsi.location.z} air destroy`)

        obsi = b.dimension.getBlockFromRay(b.center(), { x: 0, y: 1, z: 0 }, { maxDistance: 50, includePassableBlocks: false, includeTypes: ["minecraft:obsidian"] })?.block
        if (obsi.typeId == 'minecraft:obsidian')
          obsi.dimension.runCommand(`setblock ${obsi.location.x} ${obsi.location.y} ${obsi.location.z} air destroy`)
        return
      }
    }

  }
}
function ShieldBlock(player) {
  if (player.matches({ gameMode: GameMode.Creative }) || player.matches({ gameMode: GameMode.Spectator })) return;
  const score = world.scoreboard.getObjective("shield").getScore(player);
  if (score != 0) {
    player.setGameMode(GameMode.Adventure)
    if (player.dimension.getBlockFromRay({ x: player.location.x, y: player.location.y, z: player.location.z }, { x: 0, y: -1, z: 0 }, { maxDistance: 15, includePassableBlocks: false, includeTags: ["edx:runic"] })?.block == undefined)
      player.dimension.spawnParticle('edx:no_build_particle', player.location)
  }
  else {
    player.setGameMode(GameMode.Survival)
  }
}

function CameraShake(player) {
  const scoreboard = world.scoreboard.getObjective("Bow");
  const score = scoreboard.getScore(player);
  if (1 <= score) scoreboard.addScore(player, 1);
  if (1 <= score && score <= 40) {
    player.runCommand('camerashake add @s 0.002 0.05 rotational')
  }
  else if (41 <= score && score <= 60) {
    player.runCommand('camerashake add @s 0.01 0.05 rotational')
  }
  else if (61 <= score && score <= 80) {
    player.runCommand('camerashake add @s 0.015 0.05 rotational')
  }
  else if (81 <= score && score <= 120) {
    player.runCommand('camerashake add @s 0.022 0.05 rotational')
  }
  else if (121 <= score && score <= 200) {
    player.runCommand('camerashake add @s 0.029 0.05 rotational')
  }

}
function HitCooldown(player) {
  const equipment = player.getComponent('equippable');
  const selectedItem = equipment.getEquipment('Mainhand');
  //hit
  const scoreboard = world.scoreboard.getObjective("Hit_cooldown");
  const score = scoreboard.getScore(player);
  if ((1 <= score)) scoreboard.addScore(player, -1)
  if (score > 2) {
    if (player.hasTag('sword_spear_hand')) {
      var bar = "|"
      var text = bar.repeat(score) + "§8" + bar.repeat(10 - score)
      player.onScreenDisplay.setActionBar(`${text}`);
    }
  }
  else if (score == 2)
    player.onScreenDisplay.setActionBar(" ");
  //summoning_book
  const summoning_book_cooldown_score = getScore(player, 'summoning_cooldown_score')
  if (selectedItem != undefined && selectedItem.hasTag("edx:summoning_book") && summoning_book_cooldown_score > 2) {
    var cooldown_bar = "|"
    var cooldown_text = cooldown_bar.repeat(Math.round(((summoning_book_cooldown_score)) / 4)) + "§8" + cooldown_bar.repeat(22 - Math.round(((summoning_book_cooldown_score)) / 4))
    player.onScreenDisplay.setActionBar(`${cooldown_text}`);
  }
  else if (summoning_book_cooldown_score == 2)
    player.onScreenDisplay.setActionBar(" ");
  //soul_dashing_stick
  const dash_cooldown_score = getScore(player, 'dash')
  if (selectedItem != undefined && selectedItem.hasTag("edx:soul_dashing_stick") && dash_cooldown_score > 2) {
    var cooldown_bar = "|"
    var cooldown_text = cooldown_bar.repeat(Math.round(dash_cooldown_score)) + "§8" + cooldown_bar.repeat(Math.round(20 - dash_cooldown_score))
    player.onScreenDisplay.setActionBar(`${cooldown_text}`);
  }
  else if (dash_cooldown_score == 2)
    player.onScreenDisplay.setActionBar(" ");

  //dashing_stick
  if (selectedItem != undefined && selectedItem.hasTag("edx:dashing_stick") && dash_cooldown_score > 2) {
    var cooldown_bar = "|"
    var cooldown_text = cooldown_bar.repeat(Math.round(((dash_cooldown_score)) / 2)) + "§8" + cooldown_bar.repeat(22 - Math.round(((dash_cooldown_score)) / 2))
    player.onScreenDisplay.setActionBar(`${cooldown_text}`);
  }
  else if (dash_cooldown_score == 2)
    player.onScreenDisplay.setActionBar(" ");

}

function FireBreath(player) {
  const scoreboard = world.scoreboard.getObjective("Fire_breath");
  const fire = scoreboard.getScore(player);
  if (fire > 0) {
    const options = { maxDistance: 7, excludeTypes: ["minecraft:item"], excludeFamilies: ["projectile"], includePassableBlocks: false }
    var entities = world.getDimension(player.dimension.id).getEntitiesFromRay({ x: player.getHeadLocation().x, y: player.getHeadLocation().y, z: player.getHeadLocation().z } /*Position de départ*/, player.getViewDirection() /*Direction sale pute*/, options);
    for (const entity of entities) {
      if (entity.entity != player) {
        entity.entity.applyDamage(2, { cause: "fire", damagingEntity: player })
        entity.entity.setOnFire(4, true)
      }
    }
    const vmap = new MolangVariableMap();
    vmap.setVector3('variable.direction', player.getViewDirection());
    player.dimension.spawnParticle('edx:fire_breath', { x: player.getHeadLocation().x + player.getViewDirection().x / 4, y: player.getHeadLocation().y + player.getViewDirection().y / 4, z: player.getHeadLocation().z + player.getViewDirection().z / 4 }, vmap);
    scoreboard.addScore(player, -1)
  }
}

function ChargingParticle(player) {
  const bow = getScore(player, 'Bow')
  {
    if (bow > 30) {
      const equipment = player.getComponent('equippable');
      const selectedItem = equipment.getEquipment('Mainhand');
      if (selectedItem?.typeId == "edx:blaze_blade") {
        player.dimension.spawnParticle('edx:blaze_blade', { x: player.getHeadLocation().x, y: player.getHeadLocation().y, z: player.getHeadLocation().z });
      }
      else if (selectedItem?.getTags()?.includes("edx:summoning_book")) {

        player.dimension.spawnParticle('edx:summoning_book_use', { x: player.getHeadLocation().x, y: player.getHeadLocation().y, z: player.getHeadLocation().z });
      }
    }
  }

}

function BloodMoonSleep(player) {
  if (player.isSleeping && player.hasTag('blood_moon') && !player.hasTag('noinsomnia')) {
    player.runCommand('tp @s ~~1~')
    var NoSleepMessage = {
      rawtext: [{
        translate: "message.event.NoSleep",
      }]
    };
    player.onScreenDisplay.setActionBar(NoSleepMessage);
  }
}

function StrangeTotem(dimension) {
  const entityOptions = {
    type: "minecraft:item",
  }
  const entities = dimension.getEntities(entityOptions);
  for (let i = 0; i < entities.length; i++) {
    const entity = entities[i]
    var item = entity?.getComponent("minecraft:item")?.itemStack
    if (item.typeId == "edx:abomination_totem") {
      if (dimension.getBlock({ x: entity.location.x, y: entity.location.y - 1, z: entity.location.z }).typeId == "minecraft:gold_block") {
        dimension.spawnEntity("edx:abomination", entity.location)
        entity.remove()
      }

    }
  }
}
function FogAndParticle(player) {
  if (player.location.y >= 0 && player.location.y < 150 && player.dimension.id == "minecraft:overworld") {
    if (player.hasTag("mesa")) { player.runCommand("fog @s push edx:fog_mesa mesa"); player.addTag("mesaFog") }
    else if (player.hasTag('desert')) { player.runCommand("fog @s push edx:fog_desert desert"); player.addTag("desertFog") }
    else if (player.hasTag('frozen') && !player.hasTag('fur_helmet')) { player.runCommand("fog @s push edx:fog_frozen frozen"); player.addTag("frozenFog") }

    if (!player.hasTag("mesa") && player.hasTag("mesaFog")) { player.runCommand('fog @s remove mesa'); player.removeTag("mesaFog") }
    if (!player.hasTag("desert") && player.hasTag("desertFog")) { player.runCommand('fog @s remove desert'); player.removeTag("desertFog") }
    if ((!player.hasTag("frozen") || player.hasTag("fur_helmet")) && player.hasTag("frozenFog")) { player.runCommand('fog @s remove frozen'); player.removeTag("frozenFog") }
  }
  else {
    if (player.hasTag("mesaFog")) { player.runCommand('fog @s remove mesa'); player.removeTag("mesaFog") }
    if (player.hasTag("desertFog")) { player.runCommand('fog @s remove desert'); player.removeTag("desertFog") }
    if (player.hasTag("frozenFog")) { player.runCommand('fog @s remove frozen'); player.removeTag("frozenFog") }
  }

}




























