import { world,MolangVariableMap,system } from "@minecraft/server";

/*
  THIS CODE IS LAGGY
*/
export function EnlighterLink(enlighter)//from enlighter
{
  var entities = enlighter.dimension.getEntities({
    families:  ["runic"],
    location: enlighter.location,
    maxDistance: 40
  });
  for (let entity of entities) {
    if(!entity?.getProperty('edx:invincible') && entity.typeId != "edx:enlighter")
    {
      enlighter?.setDynamicProperty('linked_to',entity.id)
      enlighter.triggerEvent('link')
      entity.triggerEvent('invincible')
      entity.setProperty('edx:invincible',true)
      return
    }
  }
  enlighter.triggerEvent('no_link')
}


export function TestEnlighterLink(entity)//from invincible mobs
{
  var entities = entity.dimension.getEntities({
    families:  ["enlighter"],
    location: entity.location,
    maxDistance: 40
  });
  for (let enlighter of entities) {
    if(enlighter?.getDynamicProperty('linked_to')==entity.id)
    {
      const target = enlighter
      const dist = distance(target.location,entity.location)
      var line = Line(entity.getHeadLocation(), {x:target.location.x,y:target.location.y+1,z:target.location.z}, 0.9,dist)
      try{
         for (let loc of line) {
           entity.dimension.spawnParticle('edx:enlighter_particle', loc)
            enlighter.dimension.playSound('mob.enlighter.boost',enlighter.location)
         }
      }
      catch(e){}
      entity.setProperty('edx:invincible',true)
      return
    }
  }
  //if not found
  entity.setProperty('edx:invincible',false)
}
export function OculusLaser()
{
  const dimensions = ['overworld' ,'nether', 'the_end'].map(dim => world.getDimension(dim))
  for (const dim of dimensions){
    const oculuss = dim.getEntities({type: 'edx:oculus'});
      for (const oculus of oculuss){
        
          if(oculus?.target!=undefined)
          {
            const dist = distance(oculus.target.location,oculus.location)
            oculus?.setDynamicProperty('time',oculus?.getDynamicProperty('time')==undefined?0:oculus?.getDynamicProperty('time')+1)
            if(oculus?.getDynamicProperty('time')<60)
            {
              const vmap = new MolangVariableMap();
              vmap.setFloat('variable.color', (oculus?.getDynamicProperty('time')/150)+0.6);
              oculus.lookAt(oculus.target.location)
              for (let loc of Line({x:oculus.location.x,y:oculus.location.y+1.5,z:oculus.location.z}, {x:oculus.target.location.x,y:oculus.target.location.y+1,z:oculus.target.location.z}, 0.5,dist)) {
                dim.spawnParticle('edx:oculus_laser_particle', loc,vmap)
              }
            }
            else if(oculus?.getDynamicProperty('time')==1) {
              oculus.dimension.playSound('mob.occulus.charge',oculus.location)
            }
            else if(oculus?.getDynamicProperty('time')==60)
            {
              var line = Line({x:oculus.location.x,y:oculus.location.y+1.5,z:oculus.location.z}, {x:oculus.target.location.x,y:oculus.target.location.y+1,z:oculus.target.location.z}, 0.5,dist)
              for (let loc of line) {
                dim.spawnParticle('edx:oculus_laser_white_particle', loc)
              }
              const options = { maxDistance: distance({x:oculus.location.x,y:oculus.location.y+1.5,z:oculus.location.z},{x:oculus.target.location.x,y:oculus.target.location.y+1,z:oculus.target.location.z})+1 ,excludeTypes: ["minecraft:item"],excludeFamilies:["projectile"]}
              const location ={x:-oculus.location.x+oculus.target.location.x,y:-oculus.location.y+oculus.target.location.y,z:-oculus.location.z+oculus.target.location.z}
              system.runTimeout(() => { 
                 oculus.dimension.playSound('mob.occulus.shoot',oculus.location,{volume:20})
                const entities = dim.getEntitiesFromRay({x:oculus.location.x,y:oculus.location.y+1.5,z:oculus.location.z} /*Position de départ*/ ,location  /*Direction*/, options);
                for (let i = 0; i < entities.length && i<15; i++) {
                    try{
                      if(entities[i].entity!=oculus)
                        if(entities[i].entity.typeId=='edx:oculus')
                        {
                          entities[i].entity.kill()
                          oculus.dimension.createExplosion(entities[i].entity.location, 3, { breaksBlocks: false, causesFire: false })
                        }
                          
                        else
                          entities[i].entity.applyDamage(15,{cause: "entityAttack",damagingEntity: oculus})
                    }catch(e){}
                }
              },4
            )
              
            }
            else if(oculus?.getDynamicProperty('time')>=100)
            {
              oculus?.setDynamicProperty('time',0)
            }
          }
          else
          {
          if(oculus?.getDynamicProperty('time') != 0) {
            oculus.dimension.stopSound('mob.occulus.charge')
             oculus?.setDynamicProperty('time',0)
          }
          }
      }
    }
}

export function BondlingLink(bondling)
{
  if(bondling.getProperty("edx:linked_to_mommy")) return;//the caretaker check if it's link when it die
  var entities = bondling.dimension.getEntities({
    location: bondling.location,
    type:  "edx:bondling" ,
    maxDistance: 40
  });
  
  if(bondling?.getProperty('edx:linked')==false && bondling?.getDynamicProperty('linked_to')==undefined)
  {
    for (let entity of entities) {
      if(entity?.getDynamicProperty('linked_to')==undefined && entity?.getProperty('edx:linked')==false && entity!=bondling)
      {
        entity?.setDynamicProperty('linked_to',bondling.id)
        bondling?.setDynamicProperty('linked_to',entity.id)
        entity.triggerEvent('linked')
        bondling.triggerEvent('linked')
        break;
      }
    }
  }
  else
  {
    var isNearFriend = false
    for (let entity of entities) {
      if(entity?.getDynamicProperty('linked_to')==bondling.id && entity!=bondling)
      {
        isNearFriend=true
        break;
      }
    }
    if(!isNearFriend)
    {
      bondling.triggerEvent('stressed')
      bondling.applyKnockback({x:0,z:0}, -2)
      system.runTimeout(() => {
        bondling.applyKnockback({x:0,z:0}, -2)
      },20)
    }
  }
}


export function BondlingLine()
{
  var alreadyEntities = []
  const dimensions = ['overworld', 'nether', 'the_end'].map(dim => world.getDimension(dim))
  for (const dim of dimensions)
  {
    var entities = dim.getEntities({
      families:  ["bondling_caretaker"]
    });
    var entitiesId = entities.map(entity => entity.id)
    for (let entity of entities)
    {
      if(entity.typeId!='edx:caretaker')
      {
        var target = entities[entitiesId.indexOf(entity?.getDynamicProperty('linked_to'))]
        if(target!=undefined && !alreadyEntities.includes(entity.id) )
        {
          const dist = distance(target.location,entity.location)
          alreadyEntities.push(target.id)
          if(target.typeId=="edx:caretaker") 
          {
            var offset =2.5 //make the line go to the head of the caretaker instead of its delicious feet
            var space =1.3 // make less particles around caretakers + less tick lag if there're many bondlings
          }
          else 
          {
            var offset =0.5
            var space =1.2
          }
          var line = Line({x:entity.location.x,y:entity.location.y+0.3,z:entity.location.z}, {x:target.location.x,y:target.location.y+offset,z:target.location.z}, space,dist)
          try{
             for (let loc of line) {
               dim.spawnParticle('edx:bondling_particle', loc)
             }
          }
          catch(e){}
          
          if(dist>10)
          {
            entity.applyKnockback({x:(target.location.x-entity.location.x)/10,z:(target.location.z-entity.location.z)/10}, (target.location.y-entity.location.y)/10)
            if(target.typeId!="edx:caretaker") //don't knockback caretaker
              target.applyKnockback({x:(-target.location.x+entity.location.x)/10,z:(-target.location.z+entity.location.z)/10}, (-target.location.y+entity.location.y)/10)
          }
        }
      }
      
    }
  }
}

export function MommyHelp(bondling)
{
  if(!bondling.getProperty('edx:has_called_mommy'))
  {
    bondling.setProperty('edx:has_called_mommy',true)
    bondling.dimension.spawnEntity('edx:caretaker',bondling.location)
  }
}

export function CaretakerLink(caretaker)
{
  var entities = caretaker.dimension.getEntities({
    location: caretaker.location,
    type:  "edx:bondling" ,
    maxDistance: 40
  });
  for (let entity of entities) {
    //if(entity?.getDynamicProperty('linked_to')!=caretaker.id)
    //{
      entity?.setDynamicProperty('linked_to',caretaker.id)
      entity.triggerEvent('linked')
      entity.setProperty("edx:linked_to_mommy",true)
    //}
  }
}

export function CaretakerDie(caretaker)
{
  var entities = caretaker.dimension.getEntities({
    location: caretaker.location,
    type:  "edx:bondling" ,
    maxDistance: 40
  });
  for (let entity of entities) {
    if(entity?.getDynamicProperty('linked_to')==caretaker.id)
    {
      entity.triggerEvent('stressed')
    }
  }
}






//found on bedrock.dev discord
function distance(vector1, vector2) {
  return Math.sqrt(Math.abs(vector1.x - vector2.x)**2 + Math.abs(vector1.y - vector2.y)**2 + Math.abs(vector1.z - vector2.z)**2)
}

function Line(vector1, vector2, step2 = 1,dist) {
  let step = {
    x: (vector2.x - vector1.x) / (dist || 1),
    y: (vector2.y - vector1.y) / (dist || 1),
    z: (vector2.z - vector1.z) / (dist || 1)
  }
  let list = []
  for (let i = step2; i < dist-step2; i += step2) {
    list.push({
      x: vector1.x + i*step.x,
      y: vector1.y + i*step.y,
      z: vector1.z + i*step.z
    })
  }
  return list
}