import { ItemStack, world, BlockPermutation, system, Player, EntityComponentTypes, BlockVolume } from "@minecraft/server";
import { createVector, vectorAdd, vectorRoundDown, wiggle } from "./JMmcUtils";
import "./golem_build"
import "./glowstone";
import "./bookshelf";
import "./target";
import { boneData } from "./bone";
import "./sponge"
import "./bone"
import "./hay_golem"
import "./update_1.1"
import "./lightning_rod_golem"

world.afterEvents.playerSpawn.subscribe(event => {
  if (!event.initialSpawn) return
  const bookTag = "lb_ga:received_book"
  if (event.player.hasTag(bookTag)) return
  event.player.dimension.spawnItem(new ItemStack("lb_ga:book", 1), event.player.location)
  event.player.addTag(bookTag)
})

export function golemShortName(golemTypeId) {
  const smol = golemTypeId.split(":")[1]
  return smol.slice(0, smol.length - 6)
}

const yeetPower = {
  oak: 0.5,
  birch: 0.5,
  spruce: 0.5,
  jungle: 0.5,
  acacia: 0.5,
  dark_oak: 0.5,
  cherry: 0.5,
  mangrove: 0.5,
  bamboo: 0.5,
  warped: 0.5,
  crimson: 0.5,
  mushroom: 0.5,
  cobblestone: 0.75,
  gold: 1.25,
  diamond: 1.75,
  netherite: 3,
  sponge: 0.001,
  slime: 1,
  tnt: 1.3,
  glass: 0.4,
  glowstone: 1,
  magma: 1.2,
  ice: 1.1,
  bookshelf: 0.001,
  bone: 0.001,
  bedrock: 4,
  target: 0.001,
  //*UPDATE
  brick: 1,
  stone_bricks: 0.5,
  cauldron: 0.2,
  redstone: 1.5,
  honey: 0.5,
  cobweb: 0.01,
  pale_oak: 0.5,
  amethyst: 0.5,
  melon: 0.5,
  lapis: 0.5,
  lightning_rod: 0.7
}
world.afterEvents.entityHurt.subscribe(event => {
  const damager = event.damageSource.damagingEntity
  if (!damager) return
  if (!damager.getComponent("type_family")?.hasTypeFamily("lb_ga:golem")) return
  const shortName = golemShortName(damager.typeId)
  const power = shortName === "slime" ? yeetPower[shortName] * damager.getComponent("scale").value : yeetPower[shortName]
  const yeetedEntity = event.hurtEntity

  try {
    const direction = {
      x: yeetedEntity.location.x - damager.location.x,
      y: 0.25 * Math.abs(power),
      z: yeetedEntity.location.z - damager.location.z
    }
    function yeet(entity) {
      entity.applyKnockback(direction.x, direction.z, power, Math.abs(0.85 * power))
    }
    yeet(yeetedEntity)
  } catch (e) {

  }
})

// Random int function
function getRandomInt(min, max) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

//Spawn honey bees when honey golem is spawned in the world
world.afterEvents.entitySpawn.subscribe(e => {
  try {
    const entity = e.entity
    const dim = entity.dimension
    if (entity.typeId !== 'lb_ga:honey_golem') return
    dim.spawnEntity('lb_ga:honey_bee', entity.location)
    dim.spawnEntity('lb_ga:honey_bee', entity.location)
    dim.spawnEntity('lb_ga:honey_bee', entity.location)
  } catch (chunkError) {
    return
  }
})

//Slime behavior event
world.afterEvents.entityDie.subscribe(deathEvent => {
  try {
    const entity = deathEvent.deadEntity
    if (entity.typeId !== 'lb_ga:slime_golem') return
    let slimeTier = entity.getProperty('lb_ga:slime_tier')
    if (![0, 1].includes(slimeTier)) return
    for (let i = 1; i <= getRandomInt(2, 4); i++) {
      entity.dimension.spawnEntity(`lb_ga:slime_golem<tier_${slimeTier + 1}>`, wiggle(entity.location, 0.1))
    }
  } catch (chunkError) {
    return
  }
})

export const compostItems = [
  "minecraft:beetroot_seeds", "minecraft:dried_kelp", "minecraft:glow_berries", "minecraft:short_grass", "minecraft:tall_grass", "minecraft:fern",
  "minecraft:large_fern", "minecraft:grass_block", "minecraft:hanging_roots", "minecraft:mangrove_roots", "minecraft:kelp", "minecraft:acacia_leaves",
  "minecraft:azalea_leaves", "minecraft:birch_leaves", "minecraft:cherry_leaves", "minecraft:dark_oak_leaves", "minecraft:jungle_leaves",
  "minecraft:mangrove_leaves", "minecraft:oak_leaves", "minecraft:spruce_leaves", "minecraft:melon_seeds", "minecraft:moss_carpet", "minecraft:pink_petals",
  "minecraft:pitcher_pod", "minecraft:pumpkin_seeds", "minecraft:acacia_sapling", "minecraft:birch_sapling", "minecraft:cherry_sapling", "minecraft:dark_oak_sapling",
  "minecraft:jungle_sapling", "minecraft:oak_sapling", "minecraft:spruce_sapling", "minecraft:seagrass", "minecraft:small_dripleaf_block", "minecraft:sweet_berries",
  "minecraft:torchflower_seeds", "minecraft:wheat_seeds", "minecraft:cactus", "minecraft:dried_kelp_block", "minecraft:azalea_leaves_flowered", "minecraft:glow_lichen",
  "minecraft:melon_slice", "minecraft:nether_sprouts", "minecraft:sugar_cane", "minecraft:twisting_vines", "minecraft:vine", "minecraft:weeping_vines",
  "minecraft:apple", "minecraft:azalea", "minecraft:beetroot", "minecraft:big_dripleaf", "minecraft:carrot", "minecraft:cocoa_beans", "minecraft:dandelion",
  "minecraft:poppy", "minecraft:blue_orchid", "minecraft:allium", "minecraft:azure_bluet", "minecraft:orange_tulip", "minecraft:pink_tulip", "minecraft:red_tulip",
  "minecraft:white_tulip", "minecraft:oxeye_daisy", "minecraft:cornflower", "minecraft:lily_of_the_valley", "minecraft:torchflower", "minecraft:wither_rose",
  "minecraft:sunflower", "minecraft:lilac", "minecraft:rose_bush", "minecraft:peony", "minecraft:crimson_fungus", "minecraft:warped_fungus", "minecraft:waterlily",
  "minecraft:melon_block", "minecraft:moss_block", "minecraft:brown_mushroom", "minecraft:red_mushroom", "minecraft:mushroom_stem", "minecraft:nether_wart",
  "minecraft:potato", "minecraft:pumpkin", "minecraft:carved_pumpkin", "minecraft:crimson_roots", "minecraft:warped_roots", "minecraft:sea_pickle",
  "minecraft:shroomlight", "minecraft:spore_blossom", "minecraft:wheat", "minecraft:hay_block", "brown_mushroom_block", "red_mushroom_block",
  "minecraft:baked_potato", "minecraft:bread", "minecraft:cookie", "minecraft:flowering_azalea", "minecraft:nether_wart_block", "minecraft:pitcher_plant",
  "minecraft:warped_wart_block", "minecraft:cake", "minecraft:pumpkin_pie"
]

// Bone golem composter event
world.beforeEvents.playerInteractWithEntity.subscribe((e) => {
  const itemStack = e.itemStack
  const player = e.player
  const entity = e.target

  let equipComp = player.getComponent('equippable')
  let itemSlot = equipComp.getEquipmentSlot('Mainhand')

  if (entity.typeId === 'lb_ga:bone_golem') {
    const compostFillLevel = entity.getProperty('lb_ga:compost_fill_level')
    if (itemStack === undefined) return
    if (compostItems.includes(itemStack.typeId)) {
      const itemStackAmount = itemStack.amount
      const itemType = itemStack.type
      const newItemStackAmount = itemStack.amount - 1
      if (compostFillLevel <= 6) {
        if (compostFillLevel === 6) {
          system.run(() => {
            entity.triggerEvent(`lb_ga:fill_to_7`)
            system.runTimeout(() => {
              entity.triggerEvent('lb_ga:empty_composter')
              entity.getComponent('inventory').container.addItem(new ItemStack('minecraft:bone_meal', 16))
            }, 10)
            if (itemStackAmount >= 2) {
              let newItemStack = new ItemStack(itemType, newItemStackAmount)
              equipComp.setEquipment("Mainhand", newItemStack)
            }
            else {
              itemSlot.setItem()
            }
          })
        }
        let levelToFill = compostFillLevel + 1
        system.run(() => {
          entity.triggerEvent(`lb_ga:fill_to_${levelToFill}`)
          if (itemStackAmount >= 2) {
            let newItemStack = new ItemStack(itemType, newItemStackAmount)
            equipComp.setEquipment("Mainhand", newItemStack)
          }
          else {
            itemSlot.setItem()
          }
        })
      }
    }
    if (itemStack.typeId === "minecraft:bone_meal") {
      const itemStackAmount = itemStack.amount
      const itemType = itemStack.type
      const newItemStackAmount = itemStack.amount - 1
      const boneGolemData = boneData(entity)
      const currentBoneMeal = boneGolemData.boneMeal.get
      const maxBoneMeal = boneGolemData.boneMeal.capacity
      if (currentBoneMeal >= maxBoneMeal) return
      system.run(() => {
        if (itemStackAmount >= 2) {
          let newItemStack = new ItemStack(itemType, newItemStackAmount)
          equipComp.setEquipment("Mainhand", newItemStack)
          entity.getComponent('inventory').container.addItem(new ItemStack('minecraft:bone_meal', 1))
        }
        else {
          itemSlot.setItem()
          entity.getComponent('inventory').container.addItem(new ItemStack('minecraft:bone_meal', 1))
        }
      })
    }
  }
})

// sponge management
system.runInterval(() => {
  //Overworld
  world.getDimension("overworld").getEntities({ type: "lb_ga:sponge_golem" }).forEach(sponge => {
    let waterCount = absorbWater(sponge)
    if (sponge.getComponent('minecraft:variant').value !== undefined) {
      let currentWeather = sponge.getComponent('minecraft:variant').value
      if ((currentWeather === 1) && sponge.getProperty('lb_ga:water_count') < 65) {
        waterCount++
        sponge.setProperty('lb_ga:water_count', waterCount)
      }
    }

    spongeCommonTickEvents(sponge, waterCount)
  })

  //nether
  world.getDimension("nether").getEntities({ type: "lb_ga:sponge_golem" }).forEach(sponge => {
    let waterCount = sponge.getProperty('lb_ga:water_count')
    if (waterCount > 0) {
      waterCount -= 1
      sponge.setProperty('lb_ga:water_count', waterCount)
      sponge.dimension.playSound("random.fizz", sponge.location)
    } else {
      sponge.applyDamage(1)
      sponge.dimension.spawnParticle('minecraft:basic_smoke_particle', sponge.location)
    }

    spongeCommonTickEvents(sponge, waterCount)
  })
}, 10)

function spongeCommonTickEvents(sponge, waterCount) {
  if (waterCount < 1 && sponge.hasComponent('minecraft:is_baby')) {
    sponge.triggerEvent('lb_ga:remove_ranged_attack')
  }
  if (waterCount >= 1 && !sponge.hasComponent('minecraft:is_baby')) {
    sponge.triggerEvent('lb_ga:ranged_attack')
  }

  if (sponge.hasComponent('minecraft:onfire') && waterCount > 0) {
    sponge.extinguishFire(true)
    sponge.setProperty('lb_ga:water_count', waterCount > 10 ? waterCount - 10 : 0)
  }
}

function absorbWater(entity) {
  const center = vectorRoundDown(entity.location)
  let numberOfBlocks = entity.getProperty('lb_ga:water_count')
  const waterBlocks = entity.dimension.getBlocks(
    new BlockVolume(
      vectorAdd(center, createVector(-1, 0, -1)), vectorAdd(center, createVector(1, 3, 1))),
    { includeTypes: ["water", "flowing_water"] },
    false
  )
  for (const location of waterBlocks.getBlockLocationIterator()) {
    const block = entity.dimension.getBlock(location)
    if (numberOfBlocks < 65) {
      block.setType("air")
      numberOfBlocks += 1
    } else break
  }
  entity.setProperty("lb_ga:water_count", numberOfBlocks)
  return numberOfBlocks
}

// sponge golem detect projectile to decrement water count property
world.afterEvents.projectileHitEntity.subscribe((e) => {
  const source = e.source
  const projectile = e.projectile
  if (projectile.typeId === 'lb_ga:water_projectile' && source.typeId === 'lb_ga:sponge_golem') {
    let waterCount = source.getProperty('lb_ga:water_count')
    if (waterCount >= 1) {
      source.setProperty('lb_ga:water_count', waterCount - 1)
    } else source.triggerEvent('lb_ga:remove_ranged_attack')
    return
  }
})

world.afterEvents.projectileHitBlock.subscribe((e) => {
  const source = e.source
  const projectile = e.projectile
  if (projectile.typeId === 'lb_ga:water_projectile' && source.typeId === 'lb_ga:sponge_golem') {
    let waterCount = source.getProperty('lb_ga:water_count')
    if (waterCount >= 1) {
      source.setProperty('lb_ga:water_count', waterCount - 1)
    } else source.triggerEvent('lb_ga:remove_ranged_attack')
    return
  }
})

// Ice golem effects
system.runInterval(() => {
  //overworld
  const ow = world.getDimension('overworld')
  const owGolems = ow.getEntities({ families: ["lb_ga:golem"] })
  owGolems.forEach(ice => {
    if (ice.typeId === 'lb_ga:ice_golem') {
      try {
        let blockLocation = { x: ice.location.x, y: ice.location.y - 1, z: ice.location.z }
        let waterBlock = ow.getBlock(blockLocation)
        if (waterBlock.permutation.matches('minecraft:water')) {
          waterBlock.setPermutation(BlockPermutation.resolve('minecraft:ice'))
        }
      } catch (chunkError) { }
    }
  })
})

system.runInterval(() => {
  //overworld
  const ow = world.getDimension('overworld')
  const owGolems = ow.getEntities({ families: ["lb_ga:golem"] })
  owGolems.forEach(ice => {
    if (ice.typeId === 'lb_ga:ice_golem') {
      try {
        let blockLocation = { x: ice.location.x, y: ice.location.y - 1, z: ice.location.z }
        let waterBlock = ow.getBlock(blockLocation)
        if (waterBlock.permutation.matches('minecraft:ice')) {
          waterBlock.setPermutation(BlockPermutation.resolve('minecraft:packed_ice'))
        }
        else if (waterBlock.permutation.matches('minecraft:packed_ice')) {
          waterBlock.setPermutation(BlockPermutation.resolve('minecraft:blue_ice'))
        }
      } catch (chunkError) { }
    }
  })
}, 20)

system.runInterval(() => {
  //nether
  const nether = world.getDimension('nether')
  const netherGolems = nether.getEntities({ families: ["lb_ga:golem"] })
  netherGolems.forEach(ice => {
    if (ice.typeId === "lb_ga:ice_golem") {
      ice.applyDamage(3)
    }
  })
}, 10)

// Ice slow movement effect and extra damage vs fire types
const fireTypes = [
  "lb_ga:magma_golem", "minecraft:blaze", "minecraft:ghast",
  "minecraft:magma_cube", "minecraft:zoglin", "minecraft:strider",
  "minecraft:hoglin", "minecraft:zombie_pigman", "minecraft:piglin",
  "minecraft:piglin_brute"
]

world.afterEvents.entityHitEntity.subscribe((e) => {
  const hurtEntity = e.hitEntity
  const damager = e.damagingEntity
  if (damager.typeId === 'lb_ga:ice_golem') {
    hurtEntity.addEffect('slowness', 100, { amplifier: hurtEntity instanceof Player ? 1 : 10, showParticles: true })
    if (fireTypes.includes(hurtEntity.typeId)) {
      hurtEntity.applyDamage(7)
    }
  }
  if (fireTypes.includes(damager.typeId)) {
    if (hurtEntity.typeId === 'lb_ga:ice_golem') {
      hurtEntity.applyDamage(7)
    }
  }
})

// Wood golem burning effect
system.runInterval(() => {
  const dimensions = []
  world.getAllPlayers().forEach(player => {
    if (!dimensions.includes(player.dimension.id)) dimensions.push(player.dimension.id)
  })

  dimensions.forEach(id => {
    world.getDimension(id).getEntities({ families: ['lb_ga:wooden_golem'] }).forEach(woodGolem => {
      if (woodGolem.hasComponent('minecraft:onfire')) woodGolem.triggerEvent('lb_ga:burnt')
    })
  })
})

// Magma golem effects
const iceTypes = [
  'minecraft:snow_golem', 'minecraft:polar_bear', "minecraft:stray"
]

const waterTypes = [
  'minecraft:axolotl', 'minecraft:cod', 'minecraft:salmon',
  'minecraft:squid', 'minecraft:glow_squid', 'minecraft:pufferfish',
  'minecraft:tropical_fish', 'minecraft:turtle', 'minecraft:dolphin',
  'minecraft:drowned', 'minecraft:bogged', 'minecraft:guardian',
  'minecraft:elder_guardian'
]

world.afterEvents.entityHitEntity.subscribe((e) => {
  const hurtEntity = e.hitEntity
  const damager = e.damagingEntity
  if (damager.typeId === 'lb_ga:magma_golem') {
    if (!waterTypes.includes(hurtEntity.typeId)) hurtEntity.setOnFire(10)

    if (iceTypes.includes(hurtEntity.typeId)) hurtEntity.applyDamage(7)

    if (hurtEntity.getEffect("slowness")) hurtEntity.applyDamage(14)
  }

  if ((waterTypes.includes(damager.typeId) || iceTypes.includes(damager.typeId)) && hurtEntity.typeId === 'lb_ga:magma_golem') hurtEntity.applyDamage(7)
})

system.runInterval(() => {
  world.getDimension('overworld').getEntities({ type: "lb_ga:magma_golem" }).forEach(magma => {
    if (magma.getComponent('minecraft:variant').value !== undefined) {
      let currentWeather = magma.getComponent('minecraft:variant').value
      if (magma.isInWater || currentWeather === 1) {
        magma.applyDamage(1)
        let particleLoc = { x: magma.location.x, y: magma.location.y + 1, z: magma.location.z }
        magma.dimension.spawnParticle('minecraft:basic_smoke_particle', particleLoc)
        magma.dimension.playSound('random.fizz', particleLoc)
      }
    }
  })

  world.getDimension('nether').getEntities({ type: "lb_ga:magma_golem" }).forEach(magma => {
    const healthComponent = magma.getComponent(EntityComponentTypes.Health)
    if (healthComponent.currentValue < healthComponent.effectiveMax) healthComponent.setCurrentValue(healthComponent.currentValue + 1)
  })
}, 20)

//Amethyst golem function
world.afterEvents.entityHurt.subscribe(e => {
  const entity = e.hurtEntity
  if (entity.typeId !== 'lb_ga:amethyst_golem') return
  const healthComp = entity.getComponent('minecraft:health')
  const currentHealth = healthComp.currentValue
  const maxHealth = healthComp.effectiveMax
  const healthBeforeDamage = currentHealth + e.damage
  if (healthBeforeDamage / maxHealth >= 0.75) {
    if (currentHealth / maxHealth >= 0.75) return
      if (Math.random() <= 0.5) { // only do it half the time.
        try {
          entity.dimension.spawnItem(new ItemStack('minecraft:amethyst_shard', 1), entity.location)
        } catch (chunkError) {
          return
        }
      }
  }
})