local _, ns = ...
ns.deferred = ns.deferred or {}

local function setup()
local GSE = ns.GSE
local Statics = GSE.Static
local L = GSE.L

-- Prefer the dedicated MinimapIcon (new wrench-style PNG) when defined,
-- fall back to the legacy GSE_Logo_Dark BLP for forward/backward
-- compatibility with builds that don't have the new constant.
local iconSource = Statics.Icons.MinimapIcon or Statics.Icons.GSE_Logo_Dark

local ldb = LibStub:GetLibrary("LibDataBroker-1.1")

local function handleLeave(self)
  -- Dont close the tooltip if mouseover
  if self.tooltip and not self.tooltip:IsMouseOver() then
    self.tooltip:Release()
    self.tooltip = nil
  end
  return true
end


local function dataObject_OnLeave(self)
  -- this may throw an error - capture the error silently
  pcall(handleLeave, self)
end


local dataobj =
  ldb:NewDataObject(
  L["GSE"] .. " " .. L["Gnome Sequencer Enhanced"],
  {
    type = "data source",
    text = "GSE",
    icon = iconSource,
    OnLeave = dataObject_OnLeave
  }
)
local LibQTip = LibStub("LibQTip-2.0")
local LibSharedMedia = LibStub("LibSharedMedia-3.0")

local icon = LibStub("LibDBIcon-1.0")
local dataObjectName = L["GSE"] .. " " .. L["Gnome Sequencer Enhanced"]
icon:Register(dataObjectName, dataobj, GSEOptions.showMiniMap)

local LibDBCompartment = LibStub:GetLibrary("LibDBCompartment-1.0")
LibDBCompartment:Register(L["GSE"], dataobj)
local baseFont = CreateFont("baseFont")

-- Check for ElvUI
if GSE.isEmpty(ElvUI) then
  baseFont:SetFont(GameTooltipText:GetFont(), 10, "")
elseif LibSharedMedia:IsValid("font", ElvUI[1].db.general.font) then
  baseFont:SetFont(LibSharedMedia:Fetch("font", ElvUI[1].db.general.font), 10, "")
else
  baseFont:SetFont(GameTooltipText:GetFont(), 10, "")
end

local function CheckOOCQueueStatus()
  local output
  if GSE.OOCQueuePaused then
    -- "Paused" only when the user has explicitly toggled the queue off.
    output = GSEOptions.UNKNOWN .. L["Paused"] .. Statics.StringReset
  elseif InCombatLockdown() then
    output = GSEOptions.TitleColour .. L["Paused - In Combat"] .. Statics.StringReset
  elseif GSE.OOCQueue and #GSE.OOCQueue > 0 then
    -- Items waiting/processing out of combat.
    output = GSEOptions.CommandColour .. L["Running"] .. Statics.StringReset
  else
    -- Enabled but nothing queued.
    output = GSEOptions.UNKNOWN .. L["Idle"] .. Statics.StringReset
  end
  return output
end

local function prepareTooltipOOCLine(row, OOCEvent, oockey, rebuildFn)
  local x = row:GetCell(1)
  x:SetText(OOCEvent.action)
  x:SetJustifyH("LEFT")
  if OOCEvent.action == "UpdateSequence" then
    x = row:GetCell(3)
    x:SetText(OOCEvent.name)
    x:SetJustifyH("RIGHT")
  elseif OOCEvent.action == "Save" then
    x = row:GetCell(3)
    x:SetText(OOCEvent.sequencename)
    x:SetJustifyH("RIGHT")
  elseif OOCEvent.action == "Replace" then
    x = row:GetCell(3)
    x:SetText(OOCEvent.sequencename)
    x:SetJustifyH("RIGHT")
  elseif OOCEvent.action == "CheckMacroCreated" then
    x = row:GetCell(3)
    x:SetText(OOCEvent.sequencename)
    x:SetJustifyH("RIGHT")
  elseif OOCEvent.action == "updatemacro" then
    x = row:GetCell(3)
    x:SetText(OOCEvent.node.name)
    x:SetJustifyH("RIGHT")
  elseif OOCEvent.action == "updatevariable" then
    x = row:GetCell(3)
    x:SetText(OOCEvent.name)
    x:SetJustifyH("RIGHT")
  elseif OOCEvent.action == "importmacro" then
    x = row:GetCell(3)
    x:SetText(OOCEvent.node.name)
    x:SetJustifyH("RIGHT")
  elseif OOCEvent.action == "MergeSequence" then
    x = row:GetCell(3)
    x:SetText(OOCEvent.sequencename)
    x:SetJustifyH("RIGHT")
  end
  row:SetScript(
    "OnMouseDown",
    function()
      local label = OOCEvent.action
      if OOCEvent.action == "UpdateSequence" then
        label = label .. " (" .. (OOCEvent.name or "?") .. ")"
      elseif OOCEvent.action == "Save" or OOCEvent.action == "Replace"
          or OOCEvent.action == "MergeSequence" or OOCEvent.action == "CheckMacroCreated" then
        label = label .. " (" .. (OOCEvent.sequencename or "?") .. ")"
      elseif OOCEvent.action == "updatemacro" or OOCEvent.action == "importmacro" then
        label = label .. " (" .. (OOCEvent.node and OOCEvent.node.name or "?") .. ")"
      elseif OOCEvent.action == "updatevariable" then
        label = label .. " (" .. (OOCEvent.name or "?") .. ")"
      end
      table.remove(GSE.OOCQueue, oockey)
      GSE.Print("OOC queue: manually removed " .. label)
      rebuildFn()
    end
  )
end

function dataobj:OnEnter()
  -- Capture self so the rebuild closure can re-invoke OnEnter after a queue change.
  local buttonSelf = self
  local function rebuildTooltip()
    if buttonSelf.tooltip then
      buttonSelf.tooltip:Release()
      buttonSelf.tooltip = nil
    end
    dataobj.OnEnter(buttonSelf)
  end

  -- Acquire a tooltip with 3 columns, respectively aligned to left, center and right
  local tooltip = LibQTip:AcquireTooltip("GSE", 3, "LEFT", "CENTER", "RIGHT")
  self.tooltip = tooltip
  tooltip:SetHighlightTexture("Interface\\FriendsFrame\\UI-FriendsFrame-HighlightBar")
  tooltip:EnableMouse(true)
  tooltip:SmartAnchorTo(self)
  tooltip.OnRelease = handleLeave
  tooltip:SetAutoHideDelay(1, self)
  tooltip:Clear()
  tooltip:SetDefaultFont(baseFont)
  --tooltip:SetHeaderFont(red17font)
  local y = tooltip:AddRow()
  local x = y:GetCell(1)
  x:SetColSpan(3)
  x:SetText(L["GSE: Left Click to open the Sequence Editor"])
  x:SetJustifyH("CENTER")

  y = tooltip:AddRow()
  x = y:GetCell(1)
  x:SetColSpan(3)
  x:SetText(L["GSE: Middle Click to open the Keybinding Interface"])
  x:SetJustifyH("CENTER")

  y = tooltip:AddRow()
  x = y:GetCell(1)
  x:SetColSpan(3)
  x:SetText(L["GSE: Right Click to open the Sequence Debugger"])
  x:SetJustifyH("CENTER")

  -- If in party, add other users and their versions
  if not GSE.isEmpty(GSE.UnsavedOptions["PartyUsers"]) and GSEOptions.showGSEUsers then
    tooltip:AddSeparator()
    y = tooltip:AddHeadingRow()
    x = y:GetCell(1)
    x:SetColSpan(3)
    x:SetText(L["GSE Users"])
    x:SetJustifyH("CENTER")

    for k, v in pairs(GSE.UnsavedOptions["PartyUsers"]) do
      local userline = tooltip:AddRow(k, nil, v)
      userline:SetScript("OnMouseDown",
        function(obj, button)
          GSE.RequestSequenceList(k)
        end
      )
    end
  end

  tooltip:AddSeparator()
  y = tooltip:AddRow()
  x = y:GetCell(1)
  x:SetColSpan(3)
  x:SetFormattedText("GCD: %ss", GSE.GetGCD())
  x:SetJustifyH("CENTER")

  -- Show GSE OOCQueue Information
  if GSEOptions.showGSEoocqueue then
    tooltip:AddSeparator()
    local OOCLine = tooltip:AddRow()
    local OOCx = OOCLine:GetCell(1)
    OOCx:SetColSpan(3)
    OOCx:SetFormattedText(L["The GSE Out of Combat queue is %s"], CheckOOCQueueStatus())
    OOCx:SetJustifyH("CENTER")
    OOCLine:SetScript(
      "OnMouseDown",
      function(obj, button)
        GSE.ToggleOOCQueue()
        OOCx:SetFormattedText(L["The GSE Out of Combat queue is %s"], CheckOOCQueueStatus())
      end
    )
    tooltip:AddSeparator()
    y = tooltip:AddRow()
    if #GSE.OOCQueue > 0 then
      x = y:GetCell(1)
      x:SetColSpan(3)
      x:SetFormattedText(L["There are %i events in out of combat queue"], #GSE.OOCQueue)
      x:SetJustifyH("CENTER")
      y:SetScript(
        "OnMouseDown",
        function()
          GSE.OOCQueue = {}
          rebuildTooltip()
        end
      )
      for k, v in ipairs(GSE.OOCQueue) do
        y = tooltip:AddRow()
        prepareTooltipOOCLine(y, v, k, rebuildTooltip)
      end
    else
      -- No Items
      x = y:GetCell(1)
      x:SetColSpan(3)
      x:SetText(L["There are no events in out of combat queue"])
      x:SetJustifyH("CENTER")
    end
  end

  tooltip:AddSeparator()
  y = tooltip:AddRow()
  x = y:GetCell(1)
  x:SetColSpan(3)
  x:SetFormattedText(L["GSE Version: %s"], GSE.VersionString)
  x:SetJustifyH("CENTER")

    -- Use smart anchoring code to anchor the tooltip to our frame
  tooltip:SmartAnchorTo(self)

  -- Show it, et voil� !
  tooltip:Show()

end


function dataobj:OnLeave()
  dataObject_OnLeave(self)
end


local function normaliseMouseButton(button)
  button = tostring(button or "")
  button = button:gsub("Up$", ""):gsub("Down$", "")
  return button
end

local function ensureGUI()
  if GSE.UnsavedOptions and GSE.UnsavedOptions["GUI"] then return true end
  if GSE.CheckGUI then GSE.CheckGUI() end
  return (GSE.UnsavedOptions and GSE.UnsavedOptions["GUI"]) or GSE.ShowSequences or GSE.GUIShowDebugWindow
end

local function handleDataObjectClick(button)
  button = normaliseMouseButton(button)
  if not ensureGUI() then return end

  if button == "LeftButton" then
    if GSE.ShowSequences then GSE.ShowSequences() end
  elseif button == "MiddleButton" then
    if GSE.ShowKeyBindings then GSE.ShowKeyBindings() end
  elseif button == "RightButton" then
    if GSE.GUIShowDebugWindow then GSE.GUIShowDebugWindow() end
  end
end

function dataobj:OnClick(button)
  handleDataObjectClick(button)
end

local minimapButton = icon.GetMinimapButton and icon:GetMinimapButton(dataObjectName)
if minimapButton then
  minimapButton:RegisterForClicks("AnyUp")
end


function GSE.miniMapShow()
  icon:Show(dataObjectName)
end

function GSE.miniMapHide()
  icon:Hide(dataObjectName)
end

--- This shows or hides the minimap icon.
function GSE.MiniMapControl(show)
  -- print(show)
  if show then
    GSE.miniMapHide()
  else
    GSE.miniMapShow()
  end
end

-- GSE.MiniMapControl(GSEOptions.showMiniMap.hide)

local GCDLDB =
  ldb:NewDataObject(
  L["GSE"] .. ": " .. L["Current GCD"],
  {
    type = "data source",
    text = string.format("GCD: %ss", GSE.GetGCD()),
    icon = iconSource,
    value = GSE.GetGCD(),
    suffix = "s"
  }
)

GSE.GCDLDB = GCDLDB

GSE.LDB = true
end
table.insert(ns.deferred, setup)
