ao = ao or require('.ao')
local state = {}
local stringify = require('.stringify')
local utils = require('.utils')

Colors = { red = "\27[31m", green = "\27[32m",
  blue = "\27[34m", reset = "\27[0m", gray = "\27[90m"
}
Bell = "\x07"

Initialized = Initialized or false
Name = Name or "aos"

Owner = Owner or ""
Inbox = Inbox or {}

-- global prompt function
function Prompt()
  return "aos> "
end

local maxInboxCount = 10000

function state.insertInbox(msg)
  table.insert(Inbox, msg)
  local overflow = #Inbox - maxInboxCount
  for i = 1,overflow do
    table.remove(Inbox,1)
  end
end
local function getOwnerAddress(m)
  local _owner = nil 
  utils.map(function (k)
    local c = m.commitments[k]
    if c.alg == "rsa-pss-sha512" then
      _owner = c.committer
    elseif c.alg == "signed" and c['commitment-device'] == "ans104" then
      _owner = c.commiter
    end
  end, utils.keys(m.commitments))
  return _owner
end

local function isFromOwner(m)
  local _owner = getOwnerAddress(m)
  local _fromProcess = m['from-process'] or _owner
  return _owner ~= nil and _fromProcess == _owner
end

local function getOwner(m)
  local id = ""
  if m['from-process'] then
    return m['from-process']
  end

  utils.map(function (k)
    local c = m.commitments[k]
    if c.alg == "rsa-pss-sha512" then
      id = c.committer
    elseif c.alg == "signed" and c['commitment-device'] == "ans104" then
      id = c.committer
    end
  end, utils.keys(m.commitments)
  )
  return id
end

function state.init(req, base)
  if not Initialized then
    Owner = getOwner(base.process)
    -- if process id is equal to message id then set Owner
    -- TODO: need additional check, like msg.Slot == 1
    -- if env.Process.Id == msg.Id and Owner ~= msg.Id then
    --   Owner = env.Process['From-Process'] or msg.From
    -- end
    -- if env.Process.Name then
    --   Name = Name == "aos" and env.Process.Name
    -- end
    -- global print function
    function print(a)
      if type(a) == "table" then
        a = stringify.format(a)
      end

      if type(a) == "boolean" then
        a = Colors.blue .. tostring(a) .. Colors.reset
      end
      if type(a) == "nil" then
        a = Colors.red .. tostring(a) .. Colors.reset
      end
      if type(a) == "number" then
        a = Colors.green .. tostring(a) .. Colors.reset
      end

      if HandlerPrintLogs then
        table.insert(HandlerPrintLogs, a)
        return nil
      end

      return tostring(a)
    end

    Initialized = true
  end
end

function state.getFrom(req)
  return getOwner(req.body)
end

function state.isTrusted(req)
  if isFromOwner(req.body) then
    return true
  end
  local _trusted = false

  if req.body['from-process'] then
    _trusted = utils.includes(
      req.body['from-process'],
      ao.authorities
    )
  end

  if not _trusted then
    _trusted = utils.includes(
      getOwner(req.body), ao.authorities
    )
  end
  return _trusted
end

function state.checkSlot(req, ao)
  -- slot check
  if not ao.slot then
    ao.slot = tonumber(req.slot)
  else
    if tonumber(req.slot) ~= (ao.slot + 1) then
      print(table.concat({
      Colors.red,
      "WARNING: Slot did not match, may be due to an error generated by process",
      Colors.reset
      }))
      print("")
    end
  end
end

function state.reset(tbl)
  tbl = nil
  collectgarbage()
  return {}
end

return state
