local utils = require('lib_utils')

local initialMessages, manualMessages, defaultTitle, okay = (function()
  local config = utils.loadConfig("main_hall_notice.cfg")
  local okay = config.okay
  local title = config.title
  local manual = config.manual
  local initial = config.initial
  if not okay then ba.error("okay is missing in main_hall_notice.cfg") end
  if not title then ba.error("title is missing in main_hall_notice.cfg") end
  if not manual then ba.error("manual is missing in main_hall_notice.cfg") end
  if not initial then ba.error("initial is missing in main_hall_notice.cfg") end
  return initial, manual, title, okay
end)()

local context = (function()
  if ba.inMissionEditor() then
    return nil
  else
    return rocket:CreateContext('main_hall_notices', Vector2i.new(gr.getCenterWidth(), gr.getCenterHeight()))
  end
end)()

local enqueue, dequeue, requeue, saveQueue = (function()

  local queue = {}
  local datasaver = require("lib_data_saver")
  local needsRequeue = true

  local function saveQueue()
    datasaver:saveDataToFile("noticeQueue", queue, true)
  end

  local function enqueue(text, title)
    local text = text
    local title = title or defaultTitle
    local sentFrom = mn.getMissionFilename() .. ".fs2"
    local message = { text = text, title = title, sentFrom = sentFrom }
    table.insert(queue, message)
    saveQueue()
  end

  local function dequeue()
    return table.remove(queue, 1)
  end

  local function requeue()
    if needsRequeue then
      for _, v in ipairs(datasaver:loadDataFromFile("noticeQueue", true) or {}) do
        table.insert(queue, v)
      end
      needsRequeue = false
    end
  end

  return enqueue, dequeue, requeue, saveQueue

end)()

local draw = (function()

  local function readInitialMessages()
    local campaign = ba.getCurrentPlayer():getCampaignFilename()
    local campaignMessages = initialMessages[campaign]
    if campaignMessages then
      local datasaver = require("lib_data_saver")
      local shown = datasaver:loadDataFromFile("notice", true) or {}
      if not shown[campaign] then
        for _, message in ipairs(campaignMessages) do
          enqueue(message.text, message.title)
        end
        shown[campaign] = true
        datasaver:saveDataToFile("notice", shown, true)
      end
    end
  end

  local function dismiss()
    ui.disableInput()
    ScpuiSystem:closeDialog()
    saveQueue()
  end

  local function poll()
    readInitialMessages()
    local message = dequeue()
    if not message then return end
    -- Special case: If this message was sent from a mission and the player
    -- quit to the main hall without continuing the campaign, skip it.
    if message.sentFrom == ca.getNextMissionFilename() then return end
    -- We've got a message to show, so show it!
    local dialogs = require('lib_dialogs')
    local utils = require('lib_utils')
    local ok = utils.xstr(okay)
    dialogs.new()
           :title(utils.xstr(message.title))
           :text(ScpuiSystem:applyKeywordClasses(utils.xstr(message.text)))
           :escape(true)
           :button(dialogs.BUTTON_TYPE_POSITIVE, ok, true, string.sub(ok, 1, 1))
           :show(context)
           :continueWith(dismiss)
    -- Route user input to the new dialog.
    ui.enableInput(context)
  end

  return function()
    -- If we aren't showing a message, check if we have any.
    if not ScpuiSystem.data.DialogDoc then poll() end
    context:Update()
    context:Render()
  end

end)()

local updateEnums = (function()

  local fredList = {}
  local fredCustomList = {}

  -- Start with each notification registered, in alphabetical order.
  for n in pairs(utils.loadConfig("main_hall_notice.cfg").manual) do 
    table.insert(fredList, n)
  end
  table.sort(fredList)
  for i, n in ipairs(fredList) do
    mn.LuaEnums["MainhallNotices"]:addEnumItem(n)
  end

  return function()
    if mn.hasCustomStrings() then
      local strings = mn.CustomStrings
      local enum = mn.LuaEnums["MainhallNotices"]
  
      -- Register any new custom strings.
      for _, v in pairs(strings) do
        if v.Value == "MainhallNotice" then
          ba.print("Mainhall Notice found custom string '" .. v.Name .. "'. Adding to the list!\n")
          enum:addEnumItem(v.Name)
          table.insert(fredCustomList, v.Name)
        end
      end
  
      -- Un-register any removed custom strings.
      for i = #fredCustomList, 1, -1 do
        local found = false
        for _, v in pairs(strings) do
          if fredCustomList[i] == v.Name then
            found = true
            break
          end
        end
        if not found then
          ba.print("Mainhall Notice could not find custom string '" .. fredCustomList[i] .. "'. Removing from the list!\n")
          enum:removeEnumItem(fredCustomList[i])
          table.remove(fredCustomList, i)
        end
      end
    end
  end

end)()

mn.LuaSEXPs['send-main-hall-notice'].Action = function(always, messageName)
  -- '<none>' is required when adding SEXP enums dynamically.
  if messageName == '<none>' then return end
  -- Messages are usually drawn from the config.
  local message = manualMessages[messageName]
  -- If the message isn't in the config, it might be a custom string.
  if not message and mn.hasCustomStrings() then
    for _, v in pairs(mn.CustomStrings) do
      if v.Name == messageName then
        message = { title = v.Name, text = v.String }
      end
    end
  end
  -- We have either a message or an error condition.
  if not message then
    ba.warning('Unknown main hall notice ' .. messageName)
  elseif always or mn.isInCampaign() then
    enqueue(message.text, message.title)
  end
end

return { draw = draw, enqueue = enqueue, requeue = requeue, updateEnums = updateEnums }

