local statemachine = require("ai.statemachine")
local DL = require("design.DesignerLibrary")
local tablex = require("core.tablex")
local picklelib = require("core.pickle")
local globalLuaHooks = require("design.GlobalLuaHooks")
local traverselink = require("creature.traverselink")
traverselink.InstallHooks()
local components = require("design.components")
local timer = require("creature.timer")
globalLuaHooks.InstallHooks()
local contextactionlibrary = require("level.contextactionlibrary")
contextactionlibrary.InstallHooks()
local Brain_Core = require("behavior.corebrain")
Brain_Core:AddStateMachine(require("bandit00.equipmentBrain"))
constants = {}
global = {}
attachments = {}
global.shieldBarricadePosition = nil
global.shieldBarricadeHitCount = 0
global.shieldBarricadeHitCountMax = 1
local powerLevel = "1"
local pLevelInt = 0
local randomShieldNum = 1
local bodyType
local shieldConfigs = {
  "bandit00",
  "bandit03",
  "bandit04",
  "bandit05",
  "bandit06",
  "bandit07"
}
function LuaHookDecision_CanDevilTrigger(ai, data)
  local retVal = false
  if ai:MeterGetValue("Frost") >= 100 and ai:PickupIsAcquired("Bandit_IceArmor") == false then
    retVal = true
  end
  return retVal
end
function LuaHookDecision_CanHeal(ai, data)
  local healthPerc = ai:MeterGetValue("Health") / ai:MeterGetMax("Health")
  local retVal = false
  if healthPerc <= 0.8 then
    retVal = true
  end
  return retVal
end
function LuaHookDecision_HealthMax(ai, data)
  local healthPerc = ai:MeterGetValue("Health") / ai:MeterGetMax("Health")
  local retVal = false
  if 1 <= healthPerc then
    retVal = true
  end
  return retVal
end
function LuaHook_Shield_BlockEnterCheck(ai, data)
  local goPlayerCreature = game.Player.FindPlayer()
  local vecToPlayer = goPlayerCreature:GetWorldPosition() - ai:GetWorldPosition()
  local relativePosHero = DL.GetObjectARelativePositionToObjectB(goPlayerCreature, ai)
  local relativePosSelf = DL.GetObjectARelativePositionToObjectB(ai, goPlayerCreature)
  local defRadiusMin = 4
  local defRadiusMax = 5
  if relativePosSelf ~= "objFront" or relativePosHero ~= "objFront" or defRadiusMax < _G.global.distToPlayer then
    return data:FindOutcomeBranchesEntry("ExitBlock")
  else
    return data:FindOutcomeBranchesEntry("EnterBlock")
  end
end
function LuaHook_Shield_CoverFanatic(ai, data)
  if ai:PickupIsAcquired("GruntShield") then
    _G.global.shieldedCoverFanatic = true
  else
    _G.global.shieldedCoverFanatic = false
  end
end
function LuaHook_SonHoldInPlace(ai, data)
  local son = game.AI.FindSon()
  if DL.CheckCreatureContext(son:GetContext(), "HOLDINPLACE") == false then
    return data:FindOutcomeBranchesEntry("ExitHold")
  end
end
function LuaHookDecision_IsHeroSlowed(ai, data)
  local retVal = false
  if _G.global.target ~= nil then
    retVal = _G.global.target:PickupIsAcquired("Debuff_Hero_Frost")
  end
  return retVal
end
function LuaHookDecision_IsHelwalker(ai, data)
  if global.variant ~= nil then
    return global.variant == "HELWALKER"
  end
  return false
end
function LuaHook_Bandit_POI_ApplyColdToHotstone(ai, data)
  if global.currentPOI ~= nil then
    global.currentPOI:SendEvent("OnCreatureTriggeredEvent")
  end
end
function LuaHook_MatAnim_SeidrHealOff(ai, data)
  ai:StartMaterialAnim("seidrHeal_materialAnim_OFF")
end
function LuaHook_AddBlood_Cleave_Impact(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLowerArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLeg, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLeg, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackUpperArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLowerArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLeg, 0.1)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.1)
end
function LuaHook_AddBlood_Bandit_RageEnter(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLeg, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.1)
end
function LuaHook_AddBlood_Bandit_RageSlam(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kHead, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftChest, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kRightChest, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kFrontAbdomen, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftFrontLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBack, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kBackAbdomen, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kLeftBackLowerArm, 0.2)
  player:AddBlood(game.GameObject.eRegionId.kRightBackUpperArm, 0.4)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLowerArm, 0.2)
end
function LuaHook_AddBlood_Bandit_RageStomp(ai, data)
  local player = game.Player.FindPlayer()
  player:AddBlood(game.GameObject.eRegionId.kRightFrontLeg, 0.6)
  player:AddBlood(game.GameObject.eRegionId.kRightBackLeg, 0.3)
end
function OnAIPostSpawn(ai)
  setupCharacter(ai)
end
function Brain_Core:OnSetPowerlevelOverrideCustom(ai, global, constants, level, isElite, forced)
  powerLevel = level
  ToggleCharacterConfig(ai, forced)
end
function setupCharacter(ai)
  local player = game.Player.FindPlayer()
  local moveName = ""
  local rand = 1
  if not ai:PickupIsAcquired("GruntSword") then
    ai:PickupAcquire("GruntSword")
  end
  if StartConfig ~= nil then
    if StartConfig.BodyType ~= nil then
      bodyType = StartConfig.BodyType
    end
    if StartConfig.BodyType == nil then
      bodyType = "Helwalker"
    end
    if StartConfig.EliteDifficulty ~= nil and StartConfig.EliteDifficulty and not ai:PickupIsAcquired("Bandit00_Elite") then
      ai:PickupAcquire("Bandit00_Elite")
    end
    if bodyType == "Helwalker" and not ai:PickupIsAcquired("Bandit00_FX") then
      ai:PickupAcquire("Bandit00_FX")
    end
    if StartConfig.Equipment ~= nil and StartConfig.Equipment == "SwordAndShield" then
      if StartConfig.randomShieldNum ~= nil then
        randomShieldNum = StartConfig.randomShieldNum
      else
        randomShieldNum = math.random(1, 5)
      end
      if not ai:PickupIsAcquired("GruntShield") then
        ai:PickupAcquire("GruntShield")
        ai:PickupSetStage("GruntShield", randomShieldNum)
        constants.unawareNavBank = "NB_ShieldBank"
        if ai:PickupIsAcquired("GruntSword") then
          ai:PickupRelinquish("GruntSword")
        end
        if bodyType == "Helwalker" then
          ai:PickupAcquire("GruntShieldIceHand")
        end
      end
    end
    if StartConfig.IceArmor ~= nil and StartConfig.IceArmor == true and not ai:PickupIsAcquired("Bandit_IceArmor") then
      ai:PickupAcquire("Bandit_IceArmor")
    end
    if StartConfig.OptionalConfig ~= nil then
      if StartConfig.OptionalConfig == "Helship_Normal" then
        ai:PickupAcquire("BanditHelfireShip")
        ai:PickupAcquire("BanditNoIceBlast")
      elseif StartConfig.OptionalConfig == "Helship_Blaster" then
        ai:PickupAcquire("BanditHelfireShip")
        ai:PickupSetStage("BanditHelfireShip", 1)
        ai:PickupAcquire("BanditNoIceBlast")
      elseif StartConfig.OptionalConfig == "NoIceBlast" then
        ai:PickupAcquire("BanditNoIceBlast")
      end
    end
    if StartConfig.ShieldBarricade and ai:PickupIsAcquired("GruntShield") then
      ai:PickupAcquire("GruntShield_Barricade")
      if ai.SetDirectAimingModeIsEnabled then
        ai:SetDirectAimingModeIsEnabled(true)
      end
      if StartConfig.ShieldBarricadeHitCount ~= nil then
        global.shieldBarricadeHitCountMax = StartConfig.ShieldBarricadeHitCount
      end
    end
    if StartConfig.SpawnMove ~= nil then
      moveName = StartConfig.SpawnMove
    end
  end
  ToggleCharacterConfig(ai, not game.CHECK_FEATURE("PREEMPT_SPAWN_CONFIG"))
  if ai:IsPlayingMove("MOV_Spawn") or moveName == "BRA_Spawn" then
    DL.DebugPrint(ai, "Playing MOV_Spawn")
    if StartConfig ~= nil and string.upper(StartConfig.AggroState) ~= "INCOMBAT" then
      local rand = math.random(1, 3)
      DL.switch(rand):caseof({
        [1] = function()
          moveName = "BRA_SpawnUnaware"
          DL.DebugPrint(ai, "Picked BRA_SpawnUnaware")
        end,
        [2] = function()
          moveName = "BRA_SpawnCautious"
          DL.DebugPrint(ai, "Picked BRA_SpawnCautious")
        end,
        [3] = function()
          moveName = "BRA_SpawnVigilant"
          DL.DebugPrint(ai, "Picked BRA_SpawnVigilant")
        end,
        default = function()
          moveName = "BRA_SpawnUnaware"
        end,
        missing = function()
          moveName = "BRA_SpawnUnaware"
        end
      })
    else
      moveName = "BRA_SpawnAware"
    end
  elseif ai:IsPlayingMove("MOV_SpawnEquipShield") then
    local rand = math.random(1, 6)
    DL.switch(rand):caseof({
      [1] = function()
        moveName = "BRA_SpawnEquipShield_A"
      end,
      [2] = function()
        moveName = "BRA_SpawnEquipShield_B"
      end,
      [3] = function()
        moveName = "BRA_SpawnEquipShield_C"
      end,
      [4] = function()
        moveName = "BRA_SpawnEquipShield_D"
      end,
      [5] = function()
        moveName = "BRA_SpawnEquipShield_E"
      end,
      [6] = function()
        moveName = "BRA_SpawnEquipShield_F"
      end,
      default = function()
        moveName = "BRA_SpawnEquipShield_A"
      end,
      missing = function()
        moveName = "BRA_SpawnEquipShield_A"
      end
    })
  end
  if moveName ~= "" then
    ai:ForceMove(moveName)
  end
  if ai:AttributeGetValue("Difficulty") == 4 then
    local cineVar = game.Level.GetVariable("CompletedCineNumber")
    if ai:PickupIsAcquired("Bandit00_PowerLevel") then
      if (180 <= cineVar and 1 >= ai:PickupGetStage("Bandit00_PowerLevel") or 250 <= cineVar and 2 >= ai:PickupGetStage("Bandit00_PowerLevel") or 380 <= cineVar and 3 >= ai:PickupGetStage("Bandit00_PowerLevel") or 490 <= cineVar and 4 >= ai:PickupGetStage("Bandit00_PowerLevel")) and (cineVar < 375 or 380 < cineVar) and (ai.GroundLevel == nil or ai.GroundLevel ~= nil and string.find(ai.GroundLevel.Name, "Msp") == nil) then
        ai:PickupAcquire("PowerLevelBoost")
      end
    elseif ai:PickupIsAcquired("Bandit00_PowerLevel_Seidr") and (180 <= cineVar and ai:PickupGetStage("Bandit00_PowerLevel_Seidr") <= 0 or 250 <= cineVar and 2 >= ai:PickupGetStage("Bandit00_PowerLevel_Seidr") or 380 <= cineVar and 3 >= ai:PickupGetStage("Bandit00_PowerLevel_Seidr") or 490 <= cineVar and 4 >= ai:PickupGetStage("Bandit00_PowerLevel_Seidr")) and (ai.GroundLevel == nil or ai.GroundLevel ~= nil and string.find(ai.GroundLevel.Name, "Msp") == nil) then
      ai:PickupAcquire("PowerLevelBoost")
    end
  end
  DL.NewGamePlusLevelBoost(ai, "Bandit00_PowerLevel")
  DL.NewGamePlusLevelBoost(ai, "Bandit00_PowerLevel_Seidr")
end
function ToggleCharacterConfig(ai, override)
  if powerLevel == "1" then
    pLevelInt = 1
  elseif powerLevel == "2" then
    pLevelInt = 2
  elseif powerLevel == "3" then
    pLevelInt = 3
  elseif powerLevel == "4" then
    pLevelInt = 4
  elseif powerLevel == "5" then
    pLevelInt = 5
  elseif powerLevel == "6" then
    pLevelInt = 6
  elseif powerLevel == "7" then
    pLevelInt = 7
  elseif powerLevel == "8" then
    pLevelInt = 8
  else
    pLevelInt = powerLevel
  end
  if bodyType ~= nil then
    if bodyType == "Seidr" then
      if ai:PickupIsAcquired("Bandit00_PowerLevel") then
        ai:PickupRelinquish("Bandit00_PowerLevel")
      end
      if not ai:PickupIsAcquired("Bandit00_PowerLevel_Seidr") then
        ai:PickupAcquire("Bandit00_PowerLevel_Seidr")
      end
      if ai:PickupIsAcquired("Bandit00_PowerLevel_Seidr") then
        ai:PickupSetStage("Bandit00_PowerLevel_Seidr", pLevelInt - 1)
        if override ~= nil and override == true then
          if 5 <= pLevelInt then
            ai:SetCharacterConfig("seidr04_veryhard")
          else
            local randomConfig = math.random(1, #constants.spawnConfigsSeidrModerate)
            ai:SetCharacterConfig(constants.spawnConfigsSeidrModerate[randomConfig])
          end
        end
      end
      game.Audio.SetWwiseSwitch(ai, "CHR_Type", "Seidr")
    else
      if override ~= nil and override == true then
        if pLevelInt < 4 then
          local randomConfig = math.random(1, #constants.spawnConfigsHelwalkerModerate)
          ai:SetCharacterConfig(constants.spawnConfigsHelwalkerModerate[randomConfig])
        elseif 4 <= pLevelInt and pLevelInt < 7 then
          local randomConfig = math.random(1, #constants.spawnConfigsHelwalkerHard)
          ai:SetCharacterConfig(constants.spawnConfigsHelwalkerHard[randomConfig])
        elseif 7 <= pLevelInt then
          ai:SetCharacterConfig("Helwalker06_veryhard")
        end
        if ai:PickupIsAcquired("Bandit_IceArmor") then
          if pLevelInt < 4 then
            ai:SetCharacterConfig("HelwalkerIcy_Moderate")
          elseif 4 <= pLevelInt and pLevelInt < 7 then
            ai:SetCharacterConfig("HelwalkerIcy_Hard")
          elseif 7 <= pLevelInt then
            ai:SetCharacterConfig("HelwalkerIcy_VeryHard")
          end
        end
      end
      game.Audio.SetWwiseSwitch(ai, "CHR_Type", "Helwalker")
    end
    timer.StartCreatureTimer(0.05, function()
      for activeWeapon in ai:IterateActiveWeapons() do
        local gameObj = activeWeapon.Weapon
        if gameObj:GetName() == "sword00" then
          if bodyType == "Helwalker" then
            if pLevelInt < 4 then
              gameObj:SetCharacterConfig("helwalkerSword")
            elseif 4 <= pLevelInt then
              gameObj:SetCharacterConfig("helwalkerSword_hard")
            end
          elseif bodyType == "Seidr" then
            if pLevelInt <= 4 then
              gameObj:SetCharacterConfig("seidrSword")
            else
              gameObj:SetCharacterConfig("seidrSword_Hard")
            end
          else
            gameObj:SetCharacterConfig("banditSword")
          end
        end
        if gameObj:GetName() == "shield00" then
          if bodyType == "Helwalker" then
            gameObj:SetCharacterConfig("helWalker00")
          else
            print("randomShieldNum is " .. randomShieldNum)
            gameObj:SetCharacterConfig(shieldConfigs[randomShieldNum])
          end
        end
      end
    end)
  end
end
local hitFxTimer = 0
function Brain_Core:OnHitReaction(event, ai, global, constants)
  if ai:HasHitFlag("HIT_AXE", event.hitFlags) and ai:PickupIsAcquired("Bandit00_PowerLevel") and ai:PickupIsAcquired("Bandit_IceArmor") and hitFxTimer < game.GetGameTime() then
    game.FX.Spawn("impact_ring_small", nil, {
      Joint = "JOBack3",
      GameObject = ai,
      DeleteWithCreature = true
    })
    hitFxTimer = game.GetGameTime() + 0.5
    if ai:HasHitFlag("HIT_THROWABLE", event.hitFlags) == false then
      local concussionParams = {}
      concussionParams = {
        Tweak = "CNC_AXE_REJECT",
        WorldLocation = ai:GetWorldPosition(),
        GameObject = ai,
        EnemyId = ai:GetID()
      }
      game.Combat.PlayConcussion(concussionParams)
    end
  end
  if ai:PickupIsAcquired("GruntShield_Barricade") then
    global.shieldBarricadeHitCount = global.shieldBarricadeHitCount + 1
    if global.shieldBarricadeHitCount >= global.shieldBarricadeHitCountMax then
      ai:PickupRelinquish("GruntShield_Barricade")
    end
  end
end
function Brain_Core:OnUpdateMotion(ai, global, constants, actuatorData)
  if ai:PickupIsActive("GruntShield_Barricade") then
    actuatorData.Destination = ai:GetWorldPosition()
  end
end
local rageOn = false
function OnAIUpdate(ai)
  if Brain_Core:GetDebugTable(ai) then
    local debugTable = {}
    table.insert(debugTable, {
      "Variant:",
      global.variant
    })
    Brain_Core:AddCustomDebugTable(debugTable)
  end
  components.UpdateComponents(ai, attachments)
  traverselink.OnUpdate(ai)
  if ai ~= nil and bodyType ~= "Seidr" then
    if ai:PickupIsAcquired("Bandit_IceArmor") == true then
      if ai:PickupIsAcquired("Debuff_Slow") then
        ai:PickupRelinquish("Debuff_Slow")
      end
      if ai:PickupIsAcquired("Debuff_Frozen") then
        ai:PickupRelinquish("Debuff_Frozen")
      end
    end
    local player = game.Player.FindPlayer()
    if player:PickupIsAcquired("Debuff_Hero_Frost") then
      if ai:HasMarker("BanditFrostRage") and rageOn == false then
        ai:StartMaterialAnim("rageON")
        rageOn = true
      end
      if global.aggroState == "INCOMBAT" then
        global.target = player
        global.targetParams = "FIND_TARGET_PARAMETERS_COMBAT_KRATOS_ONLY"
      end
    elseif ai:HasMarker("BanditFrostRage") == false and rageOn == true then
      ai:StartMaterialAnim("rageOFF")
      rageOn = false
    end
  end
end
function _G.OnAICreateLuaState(ai)
  _G.OnAICreateLuaState = nil
end
function LuaHook_MatAnim_DeathFX(ai, data)
  ai:StartMaterialAnim("deathFXEmissive")
  ai:PickupAcquire("SeidrExplode_MFX_Pickup", 0)
end
function LuaHook_ClearArrow(ai, data)
  game.Combat.RemoveArrows(ai)
end
picklelib.Install()
function Pickle(GO)
  return {
    global = global
  }
end
function Unpickle(GO, t)
  global = t.global
end
