local utils = require('utils')

local context = nil

-- Add each notification to FRED in alphabetical order
-- A quirk of how this works means capitalized groups are listed before lowercase. Close enough!
local fred_list = {}
for n in pairs(utils.loadConfig("main_hall_notice.cfg").manual) do 
  table.insert(fred_list, n)
end
table.sort(fred_list)
for i,n in ipairs(fred_list) do
  mn.LuaEnums["MainhallNotices"]:addEnumItem(n)
end
--In FRED update the enums with any new custom strings
local fred_custom_list = {} --Use this to detect if an enum was removed
local function updateEnums()
  if mn.hasCustomStrings() == true then
    local strings = mn.CustomStrings
    local enum = mn.LuaEnums["MainhallNotices"]
  
  --Add any new custom strings that were added
    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(fred_custom_list, v.Name)
      end
    end
  
  --Remove any custom strings that are no longer valid
  for i = #fred_custom_list, 1, -1 do
    local found = false
      for _, v in pairs(strings) do
      if fred_custom_list[i] == v.Name then
      found = true
      break
    end
    end
    if found == false then
       ba.print("Mainhall Notice could not find custom string '" .. fred_custom_list[i] .. "'. Removing from the list!\n")
      enum:removeEnumItem(fred_custom_list[i])
    table.remove(fred_custom_list, i)
    end
  end
  end
end

if not ba.inMissionEditor() then
  context = rocket:CreateContext('main_hall_notices', Vector2i.new(gr.getCenterWidth(), gr.getCenterHeight()))
end

-- A queue for messages that we're planning to show.
local queue = {}

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 function enqueue(text, title)
  local text = text
  local title = title or defaultTitle
  local sentFrom = mn.getMissionFilename() .. ".fs2"
  table.insert(queue, { text = text, title = title, sentFrom = sentFrom })
end

local function readInitialMessages()
  local campaign = ba.getCurrentPlayer():getCampaignFilename()
  local campaignMessages = initialMessages[campaign]
  if campaignMessages then
    local datasaver = require("datasaver")
    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

-- Forward declaration
local poll

local function show(message)
  -- Use the new SCPUI to show a modal dialog!
  local dialogs = require('dialogs')
  local utils = require('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)
         -- When the dialog is closed, check for more messages.
         :continueWith(poll)
  -- Route input to our context until the user dismisses the dialog box.
  ui.enableInput(context)
end

-- Declared as local above
poll = function()
  readInitialMessages()
  if #queue > 0 then
    -- If there are any messages, show the first one. When the player dismisses
    -- that message, it will automatically call this again to check for more.
    local message = table.remove(queue, 1) 
    -- Special case: If the message was sent from a mission and the player quit to
    -- the main hall without continuing the campaign, skip this message.
    if message.sentFrom == ca.getNextMissionFilename() then
      poll()
    else
      ScpuiSystem:CloseDialog()
      show(message)
    end
  else
    -- This method name is somewhat counterintuitive (blame SCP). It "disables"
    -- SCPUI's exclusive access to user input, but it's easier to think of it as
    -- re-enabling the normal UI.
    ui.disableInput()
  end
end

local function draw()
  context:Update()
  context:Render()
end

-- SEXP operators

mn.LuaSEXPs['send-main-hall-notice'].Action = function(always, messageName)
  -- "<none>" is required when adding SEXP enums dynamically, so lets just abort if it comes up
  if messageName == "<none>" then return end
  -- This logic is written so that it always validates its arguments,
  -- even if we aren't going to send anything
  local message = manualMessages[messageName]
  --Check if the message was from a custom string
  if not message and mn.hasCustomStrings() == true then
    local strings = mn.CustomStrings
    for _, v in pairs(strings) do
      if v.Name == messageName then
        message = { title = v.Name, text = v.String }
      end
    end
  end
  if not message then
    ba.warning("Unknown main hall notice " .. messageName)
  elseif always or mn.isInCampaign() then
    enqueue(message.text, message.title)
  end
end

MainHallNotices = { poll = poll, draw = draw, enqueue = enqueue, updateEnums = updateEnums }

