local DR = select(2, ...)
local constants = DR.Modules["Core.Constants"]

local SessionState = {
  statesByItem = {},
}

local transitions = {
  [constants.SESSION.STATE.DRAFT] = {
    [constants.SESSION.STATE.OPEN] = true,
  },
  [constants.SESSION.STATE.OPEN] = {
    [constants.SESSION.STATE.COLLECTING] = true,
    [constants.SESSION.STATE.ARCHIVED] = true,
  },
  [constants.SESSION.STATE.COLLECTING] = {
    [constants.SESSION.STATE.RESOLVING] = true,
    [constants.SESSION.STATE.ARCHIVED] = true,
  },
  [constants.SESSION.STATE.RESOLVING] = {
    [constants.SESSION.STATE.ROLLOFF] = true,
    [constants.SESSION.STATE.AWARDED] = true,
    [constants.SESSION.STATE.ARCHIVED] = true,
  },
  [constants.SESSION.STATE.ROLLOFF] = {
    [constants.SESSION.STATE.ROLLOFF] = true,
    [constants.SESSION.STATE.AWARDED] = true,
    [constants.SESSION.STATE.ARCHIVED] = true,
  },
  [constants.SESSION.STATE.AWARDED] = {
    [constants.SESSION.STATE.REWARDED] = true,
    [constants.SESSION.STATE.ARCHIVED] = true,
  },
  [constants.SESSION.STATE.REWARDED] = {
    [constants.SESSION.STATE.ARCHIVED] = true,
  },
  [constants.SESSION.STATE.ARCHIVED] = {},
}

function SessionState:OnInitialize()
  self.statesByItem = self.statesByItem or {}
end

function SessionState:GetState(itemKey)
  return self.statesByItem[itemKey]
end

function SessionState:Ensure(itemKey)
  if not self.statesByItem[itemKey] then
    self.statesByItem[itemKey] = constants.SESSION.STATE.DRAFT
  end
  return self.statesByItem[itemKey]
end

function SessionState:CanTransition(itemKey, nextState)
  local current = self:Ensure(itemKey)
  return transitions[current] and transitions[current][nextState] or false
end

function SessionState:Transition(itemKey, nextState, reason)
  local current = self:Ensure(itemKey)
  if not (transitions[current] and transitions[current][nextState]) then
    local log = DR.logService and DR.logService:Get("State")
    if log then
      log:w("Illegal transition", itemKey, current, nextState, reason or "")
    end
    return false, "illegal_transition"
  end

  self.statesByItem[itemKey] = nextState

  local audit = DR.Modules["Services.Audit"]
  if audit then
    audit:Append("STATE_TRANSITION", {
      itemKey = itemKey,
      fromState = current,
      toState = nextState,
      reason = reason,
    })
  end

  if constants.SESSION.MAJOR_TRANSITIONS[nextState] then
    local comms = DR.Modules["Services.Comms"]
    if comms and comms.EmitSnapshotForTransition then
      comms:EmitSnapshotForTransition(itemKey, current, nextState, reason)
    end
  end

  return true
end

DR:RegisterModule("Services.SessionState", SessionState)
