local class = require("core.class")
local state = require("ai.state")
local statelogic = require("ai.statelogic")
local sequencelib = require("ai.sequence")
local Action = class.Class("Action", state.State)
local run_sequence = function(transient, dt)
  local current_index = transient.current_index or 1
  local elapsed_time = (transient.elapsed_time or 0) + dt
  local sequence = transient.sequence
  local sequence_point = sequence[current_index]
  if sequence_point then
    local t = sequence_point.time_absolute
    local condition = sequence_point.condition
    local advance = not t or elapsed_time >= t
    if advance and condition then
      local cancel
      advance, cancel = condition()
      if cancel then
        return true
      end
    end
    if advance then
      local callback = sequence_point.callback
      local args = sequence_point.args
      if callback and args then
        sequence_point.callback(unpack(args))
      elseif callback then
        sequence_point.callback()
      end
      current_index = current_index + 1
    end
  end
  if current_index > #sequence then
    return true
  end
  transient.current_index = current_index
  transient.elapsed_time = elapsed_time
end
function Action:enter_thunk(...)
  local enterFn = self.Enter
  if enterFn then
    local CS = statelogic.call_state()
    local ai = CS.M:GetAI(...)
    local seq = sequencelib.Sequence.New(ai)
    enterFn(self, seq, ...)
    local sequence = seq.list
    seq.list = nil
    local transient = statelogic.get_state_instance(CS.M, self.Name).transient
    transient.sequence = sequence
  end
end
function Action:update_thunk(...)
  local CS = statelogic.call_state()
  local ai = CS.M:GetAI(...)
  local dt = ai.GetFrameTime and ai:GetFrameTime() or ai:GetUnitTime()
  local transient = statelogic.get_state_instance(CS.M, self.Name).transient
  local sequence = transient.sequence
  local done = true
  if sequence then
    done = run_sequence(transient, dt)
  end
  local exitFn = self.Exit
  local updateFn = self.Update
  if done then
    if exitFn then
      exitFn(self, ...)
    end
    CS.cancel_current = true
  elseif not done and updateFn then
    updateFn(self, ...)
  end
end
return {Action = Action}
