local LD = require("design.LevelDesignLibrary")
local timers = require("level.timer")
local thisObj, thisLevel, fireObject, aiCollisionObject, preMidStateCooldown
local enemyInteracting = false
local heatMultiplerPerHit, decayPerIceBlast, regenRate
local maxHeatLevel = 100
local minHeatLevel = 0
local currentHeatLevel = minHeatLevel
local fireFX_Ignite, fireFX_Stage02, fireFX_Burst, onIgniteCallbacks, onFullyLitEnterEvents, onFullyLitExitEvents, onFullyUnlitEnterEvents, onIceBlastEvents
innerPile = nil
outerPile = nil
local decayCooldownTimer
local STATE_INIT, STATE_ACTIVE, STATE_POST_HIT, STATE_PAUSE, STATE_DISABLE = 0, 1, 2, 3, 4
local helfire_state = STATE_INIT
local STAGE_WEAKEN_THRESHOLD = 75
local STAGE_CRITICAL_THRESHOLD = 35
local MIN_HEAT_PER_HIT = 3
local STATE_FX_FULL, STATE_FX_WEAK, STATE_FX_CRIT, STATE_FX_LOW, STATE_FX_EMPTY = 1, 2, 3, 4, 5
local fx_state = STATE_FX_FULL
local ai_interacts = {}
local SetFireStage = function(stage)
  local jumpToFrame = 0
  local playToFrame = 0
  if stage == STATE_FX_FULL then
    playToFrame = 22
  elseif stage == STATE_FX_WEAK then
    jumpToFrame = 25
    playToFrame = 48
  elseif stage == STATE_FX_CRIT then
    jumpToFrame = 50
    playToFrame = 72
  elseif stage == STATE_FX_LOW then
    jumpToFrame = 75
    playToFrame = 100
  elseif stage == STATE_FX_EMPTY then
    jumpToFrame = 100
    playToFrame = 130
  end
  fireFX_Stage02:JumpAnimToFrame(jumpToFrame)
  fireFX_Stage02:PlayAnimToFrame(playToFrame)
end
local EnableFireDamage = function()
  if fireObject ~= nil then
    fireObject.LuaObjectScript.Enable()
    aiCollisionObject:Hide()
  end
end
local DisableFireDamage = function()
  if fireObject ~= nil then
    fireObject.LuaObjectScript.Disable()
    aiCollisionObject:Show()
  end
end
local UpdateRegen = function(level, object)
  local final_rate = regenRate * level:GetUnitTime()
  currentHeatLevel = currentHeatLevel + final_rate
  if currentHeatLevel > maxHeatLevel then
    currentHeatLevel = maxHeatLevel
  end
  if fx_state == STATE_FX_WEAK then
    if currentHeatLevel == maxHeatLevel then
      fx_state = STATE_FX_FULL
      SetFireStage(1)
    end
  elseif fx_state == STATE_FX_CRIT and currentHeatLevel >= STAGE_WEAKEN_THRESHOLD then
    fx_state = STATE_FX_WEAK
    SetFireStage(2)
  end
end
local SpawnFX = function(effect)
  local burst = game.FX.Spawn(effect, thisLevel, {AutoDelete = true})
  burst:SetWorldPosition(thisObj:GetWorldPosition())
end
function OnScriptLoaded(level, obj)
  thisObj = obj
  thisLevel = level
  for i = 1, 4 do
    local name = "ai_interact" .. i
    local interact = thisObj:FindSingleGOByName(name)
    table.insert(ai_interacts, interact)
  end
  heatMultiplerPerHit = obj:GetLuaTableAttribute("heatMultiplerPerHit")
  preMidStateCooldown = obj:GetLuaTableAttribute("preMidStateCooldown")
  decayPerIceBlast = obj:GetLuaTableAttribute("decayPerIceBlast")
  regenRate = obj:GetLuaTableAttribute("regenRate")
  local HelheimShip
  if obj:FindLuaTableAttribute("HelheimShip") ~= nil then
    HelheimShip = obj:GetLuaTableAttribute("HelheimShip")
  end
  fireFX_Ignite = obj:FindSingleGOByName("HotStone_Ignite")
  fireFX_Stage02 = obj:FindSingleGOByName("HotStone_Stage2")
  fireFX_Burst = obj:FindSingleGOByName("HotStone_Burst")
  fireFX_Stage02:Hide()
  fireFX_Ignite:Hide()
  fireFX_Burst:Hide()
  innerPile = thisObj:FindSingleGOByName("ReburnablePile_inner")
  outerPile = thisObj:FindSingleGOByName("OuterRoots")
  if innerPile ~= nil then
    local materialParams = {AlphaReference = 255}
    LD.SetAnimatedMaterialAttributes(innerPile, "HelRootBurnTile_A", "Burning", materialParams)
    LD.SetAnimatedMaterialAttributes(outerPile, "HelRootBurnable", "Burning", materialParams)
  end
  onFullyLitEnterEvents = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("Event_OnFullyLitEnter"))
  onFullyLitExitEvents = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("Event_OnFullyLitExit"))
  onFullyUnlitEnterEvents = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("Event_OnFullyUnlitEnter"))
  onIceBlastEvents = LD.ExtractCallbacksForEvent(level, obj, obj:FindLuaTableAttribute("Event_OnIceBlast"))
  SoundInit()
  helfire_state = STATE_DISABLE
  if HelheimShip ~= nil then
    fireObject = obj:FindSingleGOByName("CombatCollision")
    aiCollisionObject = obj:FindSingleGOByName("AICollision")
    PausePOI()
  else
    IncrementHeatLevel(100)
  end
  game.SubObject.Sleep(obj)
end
function OnStart(level, obj)
  SetHeatLevel(currentHeatLevel)
  decayCooldownTimer = timers.StartLevelTimer(preMidStateCooldown, MidstateCooldownElapsed)
  decayCooldownTimer:Stop()
  SoundOnStart()
end
local TriggerFireBlast = function(damage)
  if currentHeatLevel < maxHeatLevel then
    if enemyInteracting == false then
      RestartMidStateCooldownTimer()
    end
    if helfire_state == STATE_DISABLE then
      fireFX_Stage02:Show()
      helfire_state = STATE_ACTIVE
    end
    SpawnFX("HotStone_Ignite")
    local heat = damage * heatMultiplerPerHit
    IncrementHeatLevel(heat)
    EnableAllInteracts()
    PlayBonfireLoop()
  end
end
function OnBreakableDamaged(level, obj, attackerCreature, hitFlags, damage)
  if obj:HasHitFlag("HIT_BLADES", hitFlags) then
    TriggerFireBlast(damage)
  elseif obj:HasHitFlag("HIT_SPECIAL", hitFlags) then
    local player = game.Player.FindPlayer()
    local weapon = player:GetCurrentWeapon()
    if weapon ~= nil and weapon == "Blades" then
      TriggerFireBlast(damage)
    end
  end
end
function OnConcussionHit(level, go, attacker, hitflags, context)
  local fireBlast = engine.Hash("FIRE_BLAST")
  if fireBlast == context then
    TriggerFireBlast(20)
  elseif attacker:HasMarker("IceBlast") then
    if attacker.OwnedPOI == nil then
      return
    end
    local poi = attacker.OwnedPOI:GetGameObject().Parent
    local disable_object
    for _, interact in ipairs(ai_interacts) do
      if interact == poi then
        disable_object = poi
        break
      end
    end
    if disable_object ~= nil then
      disable_object.LuaObjectScript.Disable()
    end
    if helfire_state == STATE_DISABLE then
      return
    end
    DecrementHeatLevel(decayPerIceBlast)
    if disable_object ~= nil then
      disable_object.LuaObjectScript.Enable()
    end
    SpawnFX("HotStone_Burst")
    if currentHeatLevel <= minHeatLevel then
      fx_state = STATE_FX_EMPTY
      helfire_state = STATE_DISABLE
      fireFX_Stage02:Hide()
      DisableAllInteracts()
    else
      helfire_state = STATE_POST_HIT
    end
    LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onIceBlastEvents, "Ice Blast Events")
  end
end
function OnHitByWeapon(level, obj, weapon, weaponOwnerCreature, hitflags, context)
  if obj:HasHitFlag("HIT_BLADES", hitflags) then
    TriggerFireBlast(10)
  end
end
function IgniteObject()
  TriggerFireBlast(100)
end
function PausePOI()
  DisableAllInteracts()
end
function UnpausePOI()
  EnableAllInteracts()
end
function DisableAllInteracts()
  for _, interact in ipairs(ai_interacts) do
    interact.LuaObjectScript.Disable()
  end
end
function EnableAllInteracts()
  for _, interact in ipairs(ai_interacts) do
    interact.LuaObjectScript.Enable()
  end
end
function RestartMidStateCooldownTimer()
  if decayCooldownTimer ~= nil then
    SetMidStateBehaviorActive(false)
    decayCooldownTimer:Restart()
  end
end
function MidstateCooldownElapsed()
  if currentHeatLevel < maxHeatLevel then
    SetMidStateBehaviorActive(true)
  end
end
function StopDecayCooldownTimer()
  if decayCooldownTimer ~= nil and decayCooldownTimer.running then
    decayCooldownTimer:Reset()
  end
end
function SetMidStateBehaviorActive(value)
end
function EnemyStartedInteracting()
  enemyInteracting = true
  SetMidStateBehaviorActive(true)
end
function EnemyInterrupted()
  enemyInteracting = false
  SetMidStateBehaviorActive(false)
  if currentHeatLevel > minHeatLevel and currentHeatLevel < maxHeatLevel then
    RestartMidStateCooldownTimer()
  end
end
function EnemyCompletedInteraction()
end
function SetHeatLevel(amount)
  currentHeatLevel = amount
  UpdateFXState(currentHeatLevel)
  if currentHeatLevel >= maxHeatLevel then
    OnFullyLitEnter()
  elseif currentHeatLevel <= minHeatLevel then
    OnFullyUnlitEnter()
  end
end
function IncrementHeatLevel(amount)
  currentHeatLevel = currentHeatLevel + amount
  if currentHeatLevel >= maxHeatLevel then
    currentHeatLevel = maxHeatLevel
    OnFullyLitEnter()
    SpawnFX("HotStone_Ignite")
  end
  UpdateFXState(currentHeatLevel)
end
function DecrementHeatLevel(amount)
  if currentHeatLevel == maxHeatLevel then
    OnFullyLitExit()
  end
  currentHeatLevel = currentHeatLevel - amount
  if currentHeatLevel <= minHeatLevel then
    currentHeatLevel = minHeatLevel
    OnFullyUnlitEnter()
  end
  UpdateFXState(currentHeatLevel)
end
function GetCurrentHeatLevel()
  return currentHeatLevel
end
function GetMaxHeatLevel()
  return maxHeatLevel
end
function GetMinHeatLevel()
  return minHeatLevel
end
function UpdateFXState(HeatLevel)
  if HeatLevel == 100 then
    if helfire_state == STATE_DISABLE then
      fireFX_Stage02:Show()
      helfire_state = STATE_ACTIVE
      EnableFireDamage()
      UnpausePOI()
    end
    SetFireStage(STATE_FX_FULL)
    fx_state = STATE_FX_FULL
  elseif 80 < HeatLevel then
    SetFireStage(STATE_FX_CRIT)
    fx_state = STATE_FX_WEAK
  elseif 45 < HeatLevel then
    SetFireStage(STATE_FX_CRIT)
    fx_state = STATE_FX_CRIT
  elseif 0 < HeatLevel then
    SetFireStage(STATE_FX_LOW)
    fx_state = STATE_FX_LOW
  elseif HeatLevel == 0 then
    DisableFireDamage()
    SetFireStage(STATE_FX_EMPTY)
    fx_state = STATE_FX_EMPTY
  end
end
function OnIgnite(fn)
  if onIgniteCallbacks == nil then
    onIgniteCallbacks = {}
  end
  onIgniteCallbacks[#onIgniteCallbacks + 1] = fn
end
function FireOnIgniteCallbacks()
  if onIgniteCallbacks ~= nil then
    for _, fn in pairs(onIgniteCallbacks) do
      fn()
    end
  end
end
function ClearOnIgniteCallbacks()
  onIgniteCallbacks = nil
end
function OnFullyLitEnter()
  if enemyInteracting == false then
    SetMidStateBehaviorActive(false)
  end
  StopDecayCooldownTimer()
  FireOnIgniteCallbacks()
  LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onFullyLitEnterEvents, "Fully Lit Enter Events")
  PlayBonfireLoop()
end
function OnFullyLitExit()
  LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onFullyLitExitEvents, "Fully Lit Exit Events")
end
function OnFullyUnlitEnter()
  SetMidStateBehaviorActive(false)
  LD.ExecuteCallbacksForEvent(thisLevel, thisObj, onFullyUnlitEnterEvents, "Fully Unlit Enter Events")
  StopBonfireLoop()
end
function OnSaveCheckpoint(level, obj)
  return {currentHeatLevel = currentHeatLevel}
end
function OnRestoreCheckpoint(level, obj, savedInfo)
  currentHeatLevel = savedInfo.currentHeatLevel
end
local SNDHotStone
function SoundInit()
  SNDHotStone = thisObj:FindSingleSoundEmitterByName("SNDHotStone")
end
function SoundOnStart()
  if 0 < currentHeatLevel then
    PlayBonfireLoop()
  end
end
function PlayBonfireLoop()
  LD.PlaySound(SNDHotStone, "SND_FIRE_HelShip_Bonfire_LP")
end
function StopBonfireLoop()
  LD.StopSound(SNDHotStone, "SND_FIRE_HelShip_Bonfire_LP")
end
function GetBonfireStrengthRTPC()
  return currentHeatLevel
end
