local DL = require("design.DesignerLibrary")
local levelTimer = require("level.timer")
LD = require("design.LevelDesignLibrary")
local summonedGO, son, sonHeadJoint
local state = "init"
local counter = 0
local timer = 0
local unitTime = 0
local offsetLocation
local speed = 1.25
local treasureLocation, spawnfx, player, velocity
local dirtPuff = 5
local finalLocation
local touchPadDown = false
local markerLocation, treasureLocations, linkJointIndex
local arrowTypeIsLight = true
local upgradeLevel = 1
local nearDigsite = false
local digObject
local timerBeforeJump = 10
local nearTreasure = false
local spawnMaterialDone = true
local spawnMaterialAnimName = "creatureON"
local summonFXName = "SonTeleport_Enter"
local startNav = false
local rataSoundEmitter
function OnScriptLoaded(level, go)
  son = game.AI.FindSon()
  local sonForward = son:GetWorldForward()
  sonHeadJoint = son:GetJointIndex("JORightUpperArm1")
  linkJointIndex = son:GetJointIndex("linkJoint")
  summonedGO = game.FX.Spawn("squirrel01", level, {Scale = 0.01})
  upgradeLevel = game.Wallets.GetResourceValue("HERO", "SummonRatatoskr")
  local hero = game.Player.FindPlayer()
  if hero:PickupIsAcquired("SummonRatatoskr") then
    upgradeLevel = hero:PickupGetStage("SummonRatatoskr") + 1
  end
  if upgradeLevel == nil or upgradeLevel <= 0 then
    upgradeLevel = 1
  end
  summonedGO:SetWorldPosition(son.WorldPosition - engine.Vector.New(0, -100, 0))
  if son:PickupIsAcquired("SonArrow_Shock") then
    arrowTypeIsLight = false
    spawnMaterialAnimName = "creature_shock"
    summonFXName = "SonTeleport_Enter_Shock"
  end
  levelTimer.StartLevelTimer(0.8, function()
    if summonedGO ~= nil then
      startNav = true
      spawnfx = game.FX.Spawn(summonFXName, level, {AutoDelete = true, Scale = 0.25})
      spawnfx:SetWorldPosition(son:GetWorldJointPosition(son:GetJointIndex("JOLeftWrist1")))
      summonedGO:SetScale(1)
      SoundSpawn()
    end
  end)
  player = game.Player.FindPlayer()
  digObject = NearbyDigObject(level, go)
  local navmeshLocation
  if digObject ~= nil then
    nearDigsite = true
    navmeshLocation = game.NavMesh.ClosestLocation(digObject.WorldPosition, son)
  else
    local direction = game.Camera.GetOrbitForward()
    direction.y = 0
    local pos = player.WorldPosition + direction * 4.5
    navmeshLocation = game.NavMesh.ClosestLocation(pos, son)
  end
  if navmeshLocation ~= nil and navmeshLocation.Position ~= nil then
    treasureLocation = navmeshLocation.Position
  end
  if treasureLocation == nil then
    treasureLocation = player.WorldPosition
  end
end
function FollowLinkJoint(level, go)
  if not startNav then
    return
  end
  local offset = son:GetWorldForward() * 0.06
  if game.Combat.GetCombatStatus() then
    offset = offset - son:GetWorldLeft() * 0.03
  end
  local direction = son:GetWorldJointForward(linkJointIndex)
  summonedGO:SetWorldPosition(son:GetWorldJointPosition(linkJointIndex) + offset)
  summonedGO:SetWorldFacing(direction)
end
function OnUpdate(level, go)
  counter = counter + 1
  unitTime = level:GetUnitTime()
  if counter == 1 then
    return
  end
  if state == "init" then
    summonedGO:StartMaterialAnim("attSpecialGroundstab")
    state = "armNavStart"
    timer = 0
    summonedGO:ShowJoint(summonedGO:GetJointIndex("squirrel_stream"))
  elseif state == "armNavStart" then
    state = "armNav"
  elseif state == "armNav" then
    FollowLinkJoint(level, go)
    if son:HasMarker("RatDone") or son:HasMarker("SummonRatMarker") == false then
      if spawnMaterialDone then
        summonedGO:StartMaterialAnim(spawnMaterialAnimName)
      end
      summonedGO:StartMaterialAnim("navIdleUpright")
      state = "spawn"
      SoundClimbing()
    end
  elseif state == "spawn" then
    local sonForward = son:GetWorldForward()
    local headlocation = son:GetWorldJointPosition(sonHeadJoint)
    local offset = son:GetWorldForward() * 0.06
    if game.Combat.GetCombatStatus() then
      offset = offset - son:GetWorldLeft() * 0.03
    end
    summonedGO:SetWorldPosition(headlocation + offset)
    summonedGO:SetWorldFacing(son:GetWorldForward())
    SoundHopOff()
    state = "hopOff"
    summonedGO:StartMaterialAnim("navHop")
    timer = 0
    local player = game.Player.FindPlayer()
    local direction = (treasureLocation - son.WorldPosition):Normalized()
    velocity = direction * 2
    velocity = velocity + engine.Vector.New(0, 3, 0)
    return
  elseif state == "hopOff" then
    local summonedGOLoc = summonedGO.WorldPosition + velocity * unitTime
    velocity = velocity - engine.Vector.New(0, 10, 0) * unitTime
    summonedGO:SetWorldFacing(velocity:Normalized())
    if summonedGOLoc.y <= son.WorldPosition.y then
      summonedGOLoc.y = son.WorldPosition.y
      state = "pursue"
      summonedGO:StartMaterialAnim("navRunF_noTrans")
      speed = 3.5
    end
    summonedGO:SetWorldPosition(summonedGOLoc)
  elseif state == "pursue" then
    local direction = (treasureLocation - summonedGO.WorldPosition):Normalized()
    summonedGO:SetWorldPosition(summonedGO.WorldPosition + direction * speed * unitTime)
    summonedGO:SetWorldFacing(direction)
    if 3 > (summonedGO.WorldPosition - treasureLocation):Length() then
      summonedGO:StartMaterialAnim("navIdleUnaware01")
      state = "assess"
      velocity = direction * 2
      velocity = velocity + engine.Vector.New(0, 3, 0)
    end
  elseif state == "assess" then
    state = "dig"
    SoundDigJump()
    summonedGO:StartMaterialAnim("navHop")
    local direction = (treasureLocation - son.WorldPosition):Normalized()
    local length = (treasureLocation - summonedGO.WorldPosition):Length()
    velocity = direction * length
    velocity = velocity + engine.Vector.New(0, length * 1.1, 0)
  elseif state == "dig" then
    local summonedGOLoc = summonedGO.WorldPosition + velocity * unitTime
    summonedGO:SetWorldPosition(summonedGOLoc)
    velocity = velocity - engine.Vector.New(0, 10, 0) * unitTime
    summonedGO:SetWorldFacing(velocity:Normalized())
    if summonedGOLoc.y <= son.WorldPosition.y and 0 >= velocity.y then
      state = "explode"
      SoundDig()
      spawnfx = game.FX.Spawn("Dirt_Axe_Hit", level, {AutoDelete = true})
      spawnfx:SetWorldPosition(summonedGOLoc)
      summonedGO:SetWorldPosition(summonedGOLoc - engine.Vector.New(0, 2, 0))
      summonedGO:SetWorldFacing(engine.Vector.New(0, 1, 0))
      summonedGO:StartMaterialAnim("navIdleUnaware01")
      timer = 0
      finalLocation = summonedGOLoc
      summonedGO:HideJoint(summonedGO:GetJointIndex("squirrel_stream"))
      local spawnItem = "golootGenericHealthRune"
      if arrowTypeIsLight == false then
        spawnItem = "golootGenericRageRune"
      end
      levelTimer.StartLevelTimer(1, function()
        SummonStuff(level, go, "finished", spawnItem)
        SoundDigUpLoot()
      end)
      if 1 < upgradeLevel then
        levelTimer.StartLevelTimer(1.5, function()
          SummonStuff(level, go, "finished", spawnItem)
        end)
      end
      if 2 < upgradeLevel then
        levelTimer.StartLevelTimer(1.7, function()
          SummonStuff(level, go, "finished", spawnItem)
        end)
      end
      if nearDigsite then
        levelTimer.StartLevelTimer(1.7, function()
          digObject:CallScript("SpawnLoot", finalLocation + engine.Vector.New(math.random() - 0.5, math.random() - 0.5, math.random() - 0.5))
          digObject:CallScript("ObjectLooted")
          SoundDigUpLootSpecial()
        end)
      end
    end
  elseif state == "explode" then
    if 0.25 <= timer then
      if 0 < dirtPuff then
        local dirtfx = game.FX.Spawn("Dirt_Axe_Hit", level, {AutoDelete = true})
        dirtfx:SetWorldPosition(finalLocation)
        dirtPuff = dirtPuff - 1
      end
      timer = 0
    end
    if dirtPuff <= 0 then
      state = "finished"
      local fx = game.FX.Spawn(summonFXName, level, {AutoDelete = true})
      fx:SetWorldPosition(finalLocation)
      if summonedGO ~= nil then
        summonedGO:Destroy()
      end
      SoundDespawn()
    end
    timer = timer + unitTime
  elseif state == "finished" then
    timer = timer + unitTime
    if 25 < timer then
      if summonedGO ~= nil then
        summonedGO:Destroy()
      end
      go:Destroy()
      state = "despawned"
    end
  end
end
function SummonStuff(level, go, thisState, lootObjectName)
  if level == nil or go == nil then
    return
  end
  local spawnDirection = (game.Player.FindPlayer().WorldPosition - finalLocation):Normalized()
  spawnDirection.y = 0
  local navmeshLocation = game.NavMesh.ClosestPoint(finalLocation, game.AI.FindSon())
  if navmeshLocation ~= nil then
    finalLocation = navmeshLocation
  end
  local lootObjectSpawnArgs = {
    SpawnObject = lootObjectName,
    HookName = "OnLootSpawn",
    OffsetPosition = finalLocation,
    Level = level,
    Velocity = spawnDirection * 1.75 + engine.Vector.New(0, math.random() * 1.5 + 5, 0)
  }
  go:SpawnGameObject(lootObjectSpawnArgs)
  state = thisState
end
function NearbyDigObject(level, go)
  local goArray = game.World.FindGameObjectsByMarker("squirrelLoot", game.Player.FindPlayer().WorldPosition, 15)
  if 0 < #goArray then
    return goArray[1]
  end
  return nil
end
function SetTreasureLocation(level, go)
  if state ~= "spawn" and touchPadDown == false then
    return
  end
  local pad = player.Pad
  local vectorpoint = pad.DampedTouchPoint
  if vectorpoint ~= nil then
    local pos = game.Camera.GetOrbitPosition()
    pos.y = player.WorldPosition.y
    local direction = game.Camera.GetOrbitForward()
    direction.y = 0
    pos = pos + direction * 2
    local left = game.Camera.GetOrbitLeft()
    left.y = 0
    local percent_Y = (vectorpoint.y + 256) / 256
    local percent_X = vectorpoint.x / 256
    local pointLocation = direction + direction * 12 * percent_Y
    local scaleX = percent_Y * 6 + 2
    local leftBound = scaleX * left
    local horizontalLoc = leftBound - leftBound * percent_X * 2
    local touchLocation = pos + pointLocation + horizontalLoc
    local navmeshLocation = game.NavMesh.ClosestLocation(touchLocation, son)
    if navmeshLocation ~= nil and navmeshLocation.Position ~= nil then
      if touchPadDown == false or treasureLocation == nil then
        treasureLocation = navmeshLocation.Position
      end
      DigClue(level, go)
    end
    if pad.TouchDown == true then
      touchPadDown = true
    end
  end
end
local rumbleTimer = 0
function DigClue(level, go)
  local closestDist = 100000
  local potentialDigObject
  digObject = nil
  if treasureLocations ~= nil and treasureLocations ~= nil then
    for _, i in ipairs(treasureLocations) do
      local dist = (treasureLocation - i.WorldPosition):Length()
      if closestDist > dist then
        closestDist = dist
        potentialDigObject = i
      end
    end
  end
  local scaleAmount = 1
  nearDigsite = false
  if closestDist < 8 then
    scaleAmount = (1 - closestDist / 10) * 3 + 1
    if closestDist < 4 then
      RumbleAmount(level, go, "FFB_LARGE")
      nearDigsite = true
      digObject = potentialDigObject
    else
      RumbleAmount(level, go, "FFB_SMALL")
    end
  end
  markerLocation:SetWorldPosition(treasureLocation)
  markerLocation:SetScale(scaleAmount)
  rumbleTimer = rumbleTimer - unitTime
end
function RumbleAmount(level, go, effectName)
  if rumbleTimer <= 0 then
    local rumbleParams = {EffectName = effectName, Duration = 0.5}
    game.FX.SubmitEffect(rumbleParams)
    rumbleTimer = 0.5
  end
end
function ReturnLocations(level, go)
  local goArray = game.World.FindGameObjectsByMarker("squirrelLoot", game.Player.FindPlayer().WorldPosition, 15)
  return goArray
end
function OnLootSpawn(level, go, spawnedObject)
end
function SoundSpawn()
  rataSoundEmitter = summonedGO:FindSingleSoundEmitterByName("SNDsquirrel00")
  if rataSoundEmitter ~= nil then
    LD.PlaySoundRingOut(rataSoundEmitter, "SND_CHR_Son_Magic_Summon_Squirrel_Spawn")
    LD.PlaySoundRingOut(rataSoundEmitter, "SND_CHR_Son_Magic_Summon_Squirrel_Vocal")
  end
end
function SoundClimbing()
end
function SoundHopOff()
  LD.PlaySoundRingOut(rataSoundEmitter, "SND_CHR_Son_Magic_Summon_Squirrel_Magic")
end
function SoundDigJump()
end
function SoundDig()
  LD.PlaySoundRingOut(rataSoundEmitter, "SND_CHR_Son_Magic_Summon_Squirrel_Digging")
end
function SoundDigUpLoot()
  game.Audio.PlayBanterNonCritical("CBT_Rat_Give")
end
function SoundDigUpLootSpecial()
  game.Audio.PlayBanterNonCritical("CBT_Rat_Give")
end
function SoundDespawn()
  if arrowTypeIsLight == true then
    LD.PlaySoundRingOut(rataSoundEmitter, "SND_CHR_Son_Magic_Dissapate_A")
  else
    LD.PlaySoundRingOut(rataSoundEmitter, "SND_CHR_Son_Magic_Dissapate_B")
  end
end
