local LD = require("design.LevelDesignLibrary")
local timer = require("level.timer")
local thisLevel, thisObj, player, hitObj, testFX2, handle1Pos, frontInteractZone, currentLevel, heroPuppeteer, synchJointFacing, fxIdle, fxIdleIsOn
local attachedToPlayer = false
local crystalDestroyed = false
local onHitCallbacks, breakableObj, breakableComponent, enabled, destroyCalled, handleJointIndex
local parentObjectNotified = false
local buildUpFx, explodeFX
local explodeInProgress = false
local isTriggeringBombFace = false
local crystalMesh, rumbleParams, shakeParams, controllerVibration, concussionParams, screenShake, fxTrail
local fxTrailIsOn = false
local buildupTime = 0.7
local crystalExplodeTimer, crystalExplodeTimerDragon, interactEnableFromDropTimer, enableTrailTimer
function OnScriptLoaded(level, obj)
  obj:AddMarkerPointTest("VibrateCrystalObj")
  obj:AddMarker("SonTarget")
  thisLevel = level
  thisObj = obj
  thisObj:PauseAnim()
  player = game.Player:FindPlayer()
  handleJointIndex = obj:GetJointIndex("handle1")
  handle1Pos = obj:GetWorldJointPosition(handleJointIndex)
  breakableComponent = obj:GetBreakable()
  print("explode", explodeFX)
  enabled = obj:GetLuaTableAttribute("StartsEnabled")
  onHitCallbacks = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("OnProjectileHit"))
  crystalMesh = thisObj:FindSingleGOByName("crystalMesh")
  print("buildup fx", buildUpFx)
  fxIdle = thisObj:FindSingleGOByName("vibratecrystal_idle")
  fxIdle:Hide()
  fxTrail = thisObj:FindSingleGOByName("VibrateThrowable_Trail")
  fxTrail:Hide()
  frontInteractZone = LD.CreateInteractZone_Throwable_360(obj, "handle1")
  frontInteractZone:SetHintYRange(0.65)
  frontInteractZone:SetOnScreenPercentWeight(0)
  local throwableIconTable = {
    normal = "WORLD_INTERACT_THROWABLE",
    unavailable = "WORLD_INTERACT_UNAVAILABLE",
    locked = "WORLD_INTERACT_LOCKED",
    hint = "WORLD_INTERACT_HINT_THROWABLE"
  }
  frontInteractZone:SetPromptIconSet(throwableIconTable)
  concussionParams = {
    Tweak = "CNC_VibrateExplosion_Dragon",
    WorldLocation = handle1Pos,
    GameObject = thisObj,
    EnemyId = game.Player.FindPlayer():GetID()
  }
  rumbleParams = {
    EffectName = "FFB_GROUNDSHAKE_BUILDUP_START",
    Duration = 0.55,
    TweenInTime = 0.5
  }
  shakeParams = {
    EffectName = "FSE_CRYSTAL_EXPLODE_DRAGON",
    Duration = 0.55,
    TweenInTime = 0.5
  }
  SoundInit()
  game.SubObject.Sleep(obj)
end
function OnStart(level, obj)
  crystalMesh:SetScale(1)
end
function OnUseWorld(level, go)
  if frontInteractZone:PlayerCanInteract() then
    player:RequestInteract(thisObj, {InteractZone = frontInteractZone})
  end
end
function OnHitByArrow(level, go, arrow_owner, arrow_go, arrow_tweak)
  if arrow_go:GetName() == "electricshock_arrow_notrail" then
    CrystalHitByProjectile(level, go)
  end
end
function OnConcussionHit(level, go, attacker, hitflags, context)
  if attacker ~= nil then
    local attackerName = attacker:GetName()
    if attackerName == "earthdragon00" then
      CrystalHitByProjectile(level, go)
    end
  end
end
function OnHitGameObject(level, gameObject, attacker, hitGameObject)
  print("OnHitGameObject")
  crystalMesh:SetScale(1.2)
  attachedToPlayer = false
  local l_hitObj = hitGameObject
  if l_hitObj:GetName() == "earthdragon00" then
    hitObj = l_hitObj
    if hitObj:HasMarker("DRAGON_VULNERABLE") or hitObj:HasMarker("DRAGON_VULNERABLE_PADDED") then
      crystalMesh:SetScale(2)
      isTriggeringBombFace = true
      CrystalHitDragonFace()
    end
    PlayOnHitSound()
  else
    InteractEnable()
    PlayHitFX()
    PlayOnHitSound()
    PlayOnStuckSound()
    local handle1Pos = thisObj:GetWorldJointPosition(handleJointIndex)
    concussionParams = {
      Tweak = "CNC_VibrateBreakables",
      WorldLocation = handle1Pos,
      GameObject = thisObj,
      EnemyId = game.Player.FindPlayer():GetID()
    }
    game.Combat.PlayConcussion(concussionParams)
  end
end
function OnWeaponEmbed(level, go, attacker, weapon)
  print("ON THROW EMBED", attacker, go, weapon)
  attachedToPlayer = false
  PlayHitFX()
  crystalMesh:SetScale(1.2)
  local hitObj = go
  if hitObj:GetName() == "earthdragon00" and (hitObj:HasMarker("DRAGON_VULNERABLE") or hitObj:HasMarker("DRAGON_VULNERABLE_PADDED")) then
    CrystalHitDragonFace()
  end
  PlayOnStuckSound()
end
function GetCrystalAvailable()
  if enabled then
    return true
  else
    return false
  end
end
function LuaHookSetThrowable()
  crystalMesh:SetScale(1)
  SetThrowable(thisObj)
  LD.CallFunctionAfterDelay(PlayPickupSound, 0.1)
end
function LuaHookOnThrowRelease()
  PlayThrowSound()
end
function LuaHookDrop()
  print("LuaHookDrop")
  PlayDropSound()
  interactEnableFromDropTimer = timer.StartLevelTimer(2, InteractEnableFromDrop)
end
function SetThrowable(obj)
  local throwableTemplate = {
    name = "Light",
    attachName = "ATT_Throwable",
    standardName = "Throwable",
    range = 15,
    maxThrowRange = 30,
    reticleOffset = 0.3,
    bounciness = 0.1,
    rotationSpeed = 0.1
  }
  thisObj = obj
  attachedToPlayer = true
  DisableIdleFX()
  print("THROWABLE TRYING TO SET")
  player = game.Player:FindPlayer()
  player:SetThrowable(thisObj, throwableTemplate, "reticle")
  game.Interact.DisableTags("ThrowableCrystal")
  DisableInteract()
  enableTrailTimer = timer.StartLevelTimer(0.5, EnableTrail)
end
function PlayEmbedFX()
  EnableIdleFX()
end
function PlayHitFX()
  EnableIdleFX()
end
function EnableTrail()
  if thisObj == nil or fxTrail == nil then
    return
  end
  if not fxTrailIsOn then
    fxTrail:Show()
    fxTrailIsOn = true
  end
end
function DisableTrail()
  fxTrailIsOn = false
  fxTrail:HideParticleEmitter()
  fxTrail:Hide()
end
function EnableIdleFX()
  fxIdle:Show()
  fxIdleIsOn = true
end
function DisableIdleFX()
  if fxIdleIsOn then
    fxIdleIsOn = false
    fxIdle:HideParticleEmitter()
    fxIdle:Hide()
  end
end
function CrystalHitDragonFace()
  if thisObj == nil then
    return
  end
  if not explodeInProgress and crystalDestroyed ~= true then
    explodeInProgress = true
    if rumbleParams == nil then
      rumbleParams = {
        EffectName = "FFB_GROUNDSHAKE_BUILDUP_START",
        Duration = 0.55,
        TweenInTime = 0.5
      }
    end
    game.FX.SubmitEffect(rumbleParams)
    if shakeParams == nil then
      shakeParams = {
        EffectName = "FSE_CRYSTAL_EXPLODE_DRAGON",
        Duration = 0.55,
        TweenInTime = 0.5
      }
    end
    buildUpFx = game.FX.Spawn("vibrate_buildUp_dragon", thisLevel, {
      GameObject = thisObj,
      Joint = "handle1",
      Follow = true,
      AutoDelete = true
    })
    PlayVibrateSound()
    crystalExplodeTimer = _G.StartLevelTimer(buildupTime, function()
      CrystalExplodeDragon()
    end)
  end
end
function CrystalHitByProjectile()
  if thisObj == nil then
    return
  end
  if not explodeInProgress and crystalDestroyed ~= true then
    explodeInProgress = true
    DisableInteract()
    buildUpFx = game.FX.Spawn("vibrate_buildUp_dragon", thisLevel, {
      GameObject = thisObj,
      Joint = "handle1",
      Follow = true,
      AutoDelete = true
    })
    if rumbleParams == nil then
      rumbleParams = {
        EffectName = "FFB_GROUNDSHAKE_BUILDUP_START",
        Duration = 0.55,
        TweenInTime = 0.5
      }
    end
    game.FX.SubmitEffect(rumbleParams)
    if shakeParams == nil then
      shakeParams = {
        EffectName = "FSE_CRYSTAL_EXPLODE_DRAGON",
        Duration = 0.55,
        TweenInTime = 0.5
      }
    end
    game.FX.SubmitEffect(shakeParams)
    PlayVibrateSound()
    crystalExplodeTimerDragon = _G.StartLevelTimer(buildupTime, function()
      CrystalExplode()
    end)
  end
end
function CrystalExplodeDragon()
  if thisObj == nil then
    return
  end
  explodeFX = game.FX.Spawn("vibrate_explosionDragon", thisLevel, {
    GameObject = thisObj,
    Joint = "handle1",
    Follow = true,
    AutoDelete = true
  })
  if fxTrailIsOn then
    DisableTrail()
  end
  if breakableComponent.Broken == false then
    breakableComponent:Break()
  end
  PlaySoundDetonateDragon()
end
function CrystalExplode()
  if thisObj == nil then
    return
  end
  explodeFX = game.FX.Spawn("vibrate_explosionDragon", thisLevel, {
    GameObject = thisObj,
    Joint = "handle1",
    Follow = true,
    AutoDelete = true
  })
  if fxTrailIsOn then
    DisableTrail()
  end
  if attachedToPlayer then
    game.Interact.EnableTags("ThrowableCrystal")
  end
  if breakableComponent.Broken == false then
    breakableComponent:Break()
  end
  PlaySoundDetonate()
end
function OnBreakableBroken(level, obj)
  thisObj:RemoveMarker("VibrateCrystalObj")
  thisObj:RemoveMarker("SonTarget")
  explodeFX = game.FX.Spawn("vibrate_explosionDragon", thisLevel, {
    GameObject = thisObj,
    Joint = "handle1",
    Follow = true,
    AutoDelete = true
  })
  crystalDestroyed = true
  local handle1Pos = obj:GetWorldJointPosition(handleJointIndex)
  game.Combat.PlayConcussion(concussionParams)
  explodeInProgress = true
  DisableInteract()
  if hitObj ~= nil and isTriggeringBombFace then
    hitObj:TriggerMoveEvent("bombFace")
    isTriggeringBombFace = false
  end
  LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onHitCallbacks, "CrystalHitByProjectile")
  PlaySoundDetonate()
end
function OnInteractStart(level, obj, creature)
  print("got interact start msg")
  player:MarkCurrentWeaponMode()
  EndPickupThrowable()
  heroPuppeteer = game.Puppeteer.NewForce(obj, "Throwable Pickup", player)
  heroPuppeteer:WeaponEquip({weaponMode = "Bare"})
  heroPuppeteer:StartBranch("BRA_PickUpThrowable")
  heroPuppeteer:OnComplete(EndPickupThrowable)
end
function OnInteractAbort(level, obj, creature)
  print("got interact Abort msg")
  game.Interact.EnableTags("ThrowableCrystal")
end
function OnInteractFinish(level, obj, creature)
end
function OnInteractDone(level, obj, creature)
  print("got interact done msg")
end
function EnableObject(data)
  if data == false then
    enabled = false
  elseif data == true then
    enabled = true
  end
end
function InteractEnableFromDrop()
  enabled = true
  if frontInteractZone == nil or thisObj == nil then
    return
  else
    frontInteractZone:Enable()
  end
end
function InteractEnable()
  enabled = true
  game.Interact.EnableTags("ThrowableCrystal")
  if frontInteractZone == nil or thisObj == nil then
    return
  else
    frontInteractZone:Enable()
  end
end
function DisableInteract()
  if frontInteractZone == nil or thisObj == nil then
    return
  else
    frontInteractZone:Disable()
  end
end
function EndPickupThrowable()
  if heroPuppeteer ~= nil then
    heroPuppeteer:Clear()
    heroPuppeteer:DetachPuppet()
    heroPuppeteer = nil
  end
end
function OnSpawnedObjectDestroyed(level, spawn)
  game.Interact.EnableTags("ThrowableCrystal")
  print("child NOTIFICATION...I GOT DESTROYEED")
end
local soundEmitter, soundEmitterBroken
local soundDetonationSFXFired = false
local soundEvents = {
  OnIdle = "SND_WPN_Bifrost_Bomb_Idle_LP",
  OnPickup = "SND_WPN_Bifrost_Bomb_Pick_Up",
  OnHeld = "SND_WPN_Bifrost_Bomb_Hold_Active_LP",
  OnThrow = "SND_WPN_Bifrost_Bomb_Throw",
  OnThrowLP = "SND_WPN_Bifrost_Bomb_Throw_LP",
  OnDrop = "SND_WPN_Bifrost_Bomb_Drop_Release",
  OnHit = "SND_WPN_Bifrost_Bomb_Hit_Surface",
  OnStuck = "SND_WPN_Bifrost_Bomb_Throw_Hit_Latch",
  OnVibrate = "SND_WPN_Bifrost_Bomb_Explo_Build_Up_LP",
  OnDetonate = "SND_WPN_Bifrost_Bomb_Explo",
  OnDetonateDragon = "SND_CHR_EarthDragon_Crystal_Hit"
}
function SoundInit()
  soundEmitter = thisObj:FindSingleSoundEmitterByName("SNDThrowableVibrate_Pristine")
  soundEmitterBroken = thisObj:FindSingleSoundEmitterByName("SNDThrowableVibrate_Broken")
  LD.CallFunctionAfterDelay(PlaySpawnSound, 0.3)
end
function PlaySpawnSound()
  print("PlaySpawnSound")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  LD.PlaySound(soundEmitter, soundEvents.OnHeld)
end
function PlayPickupSound()
  print("PlayPickupSound")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  LD.PlaySound(soundEmitter, soundEvents.OnPickup)
  LD.PlaySound(soundEmitter, soundEvents.OnHeld)
  LD.StopSound(soundEmitter, soundEvents.OnIdle)
end
function PlayThrowSound()
  print("PlayThrowSound")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  LD.PlaySound(soundEmitter, soundEvents.OnThrow)
  LD.PlaySound(soundEmitter, soundEvents.OnThrowLP)
  LD.StopSound(soundEmitter, soundEvents.OnHeld)
end
function PlayOnHitSound()
  print("PlayOnHitSound")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  LD.PlaySound(soundEmitter, soundEvents.OnHit)
  LD.StopSound(soundEmitter, soundEvents.OnThrowLP)
  LD.PlaySound(soundEmitter, soundEvents.OnIdle)
end
function PlayOnStuckSound()
  print("PlayOnStuckSound")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  LD.PlaySound(soundEmitter, soundEvents.OnStuck)
end
function PlayDropSound()
  print("PlayDropSound")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  LD.PlaySound(soundEmitter, soundEvents.OnDrop)
  LD.StopSound(soundEmitter, soundEvents.OnHeld)
  LD.PlaySound(soundEmitter, soundEvents.OnIdle)
end
function PlayVibrateSound()
  print("PlayVibrateSound")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  LD.PlaySound(soundEmitter, soundEvents.OnVibrate)
end
function PlaySoundDetonate()
  print("PlaySoundDetonate")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  if not soundDetonationSFXFired then
    soundDetonationSFXFired = true
    LD.PlaySoundAfterDelay(soundEmitterBroken, soundEvents.OnDetonate, 0.1)
    LD.StopSoundAfterDelay(soundEmitter, soundEvents.OnVibrate, 0.1)
    LD.StopSoundAfterDelay(soundEmitter, soundEvents.OnIdle, 0.1)
  end
end
function PlaySoundDetonateDragon()
  print("PlaySoundDetonateDragon")
  if thisObj == nil or soundEmitter == nil then
    print("thisObj or soundEmitter is nil, exiting")
    return
  end
  if not soundDetonationSFXFired then
    soundDetonationSFXFired = true
    LD.PlaySoundAfterDelay(soundEmitterBroken, soundEvents.OnDetonateDragon, 0.1)
    LD.StopSoundAfterDelay(soundEmitter, soundEvents.OnVibrate, 0.1)
    LD.StopSoundAfterDelay(soundEmitter, soundEvents.OnIdle, 0.1)
    LD.StopSoundAfterDelay(soundEmitter, soundEvents.OnThrowLP, 0.1)
  end
end
function OnTeardown()
  if crystalExplodeTimer ~= nil then
    crystalExplodeTimer:Stop()
  end
  if crystalExplodeTimerDragon ~= nil then
    crystalExplodeTimerDragon:Stop()
  end
  if interactEnableFromDropTimer ~= nil then
    interactEnableFromDropTimer:Stop()
  end
  if enableTrailTimer ~= nil then
    enableTrailTimer:Stop()
  end
end
