local AddonName, MDT = ...
local L = MDT.L
local mainFrameStrata = "HIGH"
local canvasDrawLayer = "BORDER"
local navigationSidebarWidth = 42
local panelHeight = 30
local defaultIconTexture = "Interface\\AddOns\\"..AddonName.."\\Textures\\navigationSidebarIcons"

MDT.navigationSections = {}
MDT.navigationSectionLookup = {}

function MDT:RegisterNavigationSection(section)
  assert(section.key, "Navigation section requires a key")
  assert(not self.navigationSectionLookup[section.key], "Duplicate navigation section: "..section.key)
  section.createContentFrame = section.createContentFrame ~= false
  section.createSidePanelFrame = section.createSidePanelFrame ~= false
  section.texture = section.texture or defaultIconTexture
  section.onShow = section.onShow or function() end
  self.navigationSectionLookup[section.key] = section
  table.insert(self.navigationSections, section)
  return section
end

function MDT:GetNavigationSections()
  return self.navigationSections
end

function MDT:GetNavigationSection(sectionKey)
  return self.navigationSectionLookup[sectionKey]
end

function MDT:IsValidNavigationSection(sectionKey)
  return self:GetNavigationSection(sectionKey) ~= nil
end

MDT:RegisterNavigationSection({
  key = "maps",
  tooltip = L["Maps"],
  texCoords = { 0, 0.25, 0, 0.25 },
  iconOffsetY = -0.5,
  createContentFrame = false,
  createSidePanelFrame = false,
})

function MDT:GetNavigationSidebarWidth()
  return navigationSidebarWidth
end

function MDT:GetCurrentSection()
  local db = MDT:GetDB()
  if db then
    if not self:IsValidNavigationSection(db.currentSection) then db.currentSection = "maps" end
    return db.currentSection
  end
  if not self:IsValidNavigationSection(self.currentSection) then self.currentSection = "maps" end
  return self.currentSection
end

function MDT:IsMapSectionActive()
  return self:GetCurrentSection() == "maps"
end

local function setShown(region, shown)
  local frame = region and (region.frame or region)
  if not frame then return end
  if shown then
    frame:Show()
  else
    frame:Hide()
  end
end

local function closeAceDropdown(widget)
  if not widget or not widget.pullout then return end
  widget.pullout:Close()
  if widget.pullout.frame then widget.pullout.frame:Hide() end
end

function MDT:SetCurrentSection(sectionKey)
  if not self:IsValidNavigationSection(sectionKey) then sectionKey = "maps" end
  local db = MDT:GetDB()
  if db then
    db.currentSection = sectionKey
  else
    self.currentSection = sectionKey
  end
  MDT:UpdateSectionVisibility()
end

function MDT:UpdateSectionVisibility()
  local frame = MDT.main_frame
  if not frame then return end
  local db = MDT:GetDB()
  local currentSection = MDT:GetCurrentSection()
  local showMapControls = currentSection == "maps"

  if frame.navigationSidebar and frame.navigationSidebar.buttons then
    for sectionKey, button in pairs(frame.navigationSidebar.buttons) do
      local active = sectionKey == currentSection
      if button.activeTexture then setShown(button.activeTexture, active) end
    end
  end

  setShown(frame.scrollFrame, showMapControls)
  setShown(frame.mapPanelFrame, showMapControls)

  if frame.toolbar then
    setShown(frame.toolbar.toggleButton, showMapControls)
    if showMapControls and db and db.toolbarExpanded then
      frame.toolbar:Show()
    else
      frame.toolbar:Hide()
    end
  end

  if frame.sidePanel then
    setShown(frame.sidePanel.WidgetGroup, showMapControls)
    if frame.sidePanel.WidgetGroup then
      setShown(frame.sidePanel.WidgetGroup.PresetDropDown, showMapControls)
    end
    setShown(frame.sidePanelNewButton, showMapControls)
    setShown(frame.sidePanelRenameButton, showMapControls)
    setShown(frame.sidePanelDeleteButton, showMapControls)
    setShown(frame.sidePanelExportButton, showMapControls)
    setShown(frame.sidePanelImportButton, showMapControls)
    setShown(frame.LinkToChatButton, showMapControls)
    setShown(frame.LiveSessionButton, showMapControls)
    setShown(frame.sidePanel.DifficultySlider, showMapControls)
    setShown(frame.sidePanel.middleLine, showMapControls)
    setShown(frame.sidePanel.PullButtonScrollGroup, showMapControls)
    setShown(frame.sidePanel.ProgressBar, showMapControls)
    if not showMapControls then
      closeAceDropdown(frame.sidePanel.WidgetGroup and frame.sidePanel.WidgetGroup.PresetDropDown)
    end
  end

  if frame.seasonSelectionGroup then setShown(frame.seasonSelectionGroup, showMapControls) end
  if frame.sublevelSelectionGroup then setShown(frame.sublevelSelectionGroup, showMapControls) end
  if not showMapControls then
    closeAceDropdown(frame.seasonSelectionGroup and frame.seasonSelectionGroup.seasonDropdown)
    closeAceDropdown(frame.sublevelSelectionGroup and frame.sublevelSelectionGroup.sublevelDropdown)
  end
  if MDT.UpdateDungeonSelectVisibility then MDT:UpdateDungeonSelectVisibility(showMapControls) end

  if frame.sectionContentFrames then
    for sectionKey, sectionFrame in pairs(frame.sectionContentFrames) do
      setShown(sectionFrame, sectionKey == currentSection)
    end
  end
  if frame.sectionSidePanelFrames then
    for sectionKey, sectionFrame in pairs(frame.sectionSidePanelFrames) do
      setShown(sectionFrame, sectionKey == currentSection)
    end
  end

  local sectionChanged = frame.lastVisibleSection ~= currentSection
  frame.lastVisibleSection = currentSection
  local currentSectionConfig = MDT:GetNavigationSection(currentSection)
  currentSectionConfig.onShow(sectionChanged)
end

function MDT:MakeNavigationSidebar(frame)
  if frame.navigationSidebar == nil then
    frame.navigationSidebar = CreateFrame("Frame", "MDTNavigationSidebar", frame)
    frame.navigationSidebar:SetFrameStrata(mainFrameStrata)
    frame.navigationSidebar:SetFrameLevel(4)
    frame.navigationSidebar.tex = frame.navigationSidebar:CreateTexture(nil, "BACKGROUND", nil, 0)
    frame.navigationSidebar.tex:SetAllPoints()
    frame.navigationSidebar.tex:SetDrawLayer(canvasDrawLayer, -5)
    frame.navigationSidebar.tex:SetColorTexture(unpack(MDT.BackdropColor))
    frame.navigationSidebar.buttons = {}
    MDT:RegisterMainFrameDragHandle(frame.navigationSidebar, frame)

    local sections = MDT:GetNavigationSections()
    local buttonSize = 36
    local iconSize = 31
    local firstButtonTopOffset = -panelHeight

    for idx, section in ipairs(sections) do
      local button = CreateFrame("Button", "MDTNavigationSidebarButton"..idx, frame.navigationSidebar)
      button.frame = button
      button.type = "button"
      button.sectionKey = section.key
      button.tooltipText = section.tooltip
      button:SetSize(buttonSize, buttonSize)
      button:SetPoint("TOP", frame.navigationSidebar, "TOP", 0, firstButtonTopOffset - ((idx - 1) * (buttonSize + 6)))
      button:RegisterForClicks("AnyUp")

      local active = button:CreateTexture(nil, "BACKGROUND", nil, 1)
      active:SetAllPoints()
      active:SetColorTexture(1, 1, 1, 0.14)
      active:Hide()
      button.activeTexture = active

      local icon = button:CreateTexture(nil, "ARTWORK", nil, 0)
      icon:SetTexture(section.texture)
      icon:SetTexCoord(unpack(section.texCoords))
      icon:SetSize(section.iconSize or iconSize, section.iconSize or iconSize)
      icon:SetPoint("CENTER", button, "CENTER", section.iconOffsetX or 0, section.iconOffsetY or 0)
      icon:SetVertexColor(1, 1, 1, 0.9)
      button:SetNormalTexture(icon)

      local pushed = button:CreateTexture(nil, "ARTWORK", nil, 0)
      pushed:SetTexture(section.texture)
      pushed:SetTexCoord(unpack(section.texCoords))
      pushed:SetSize(section.iconSize or iconSize, section.iconSize or iconSize)
      pushed:SetPoint("CENTER", button, "CENTER", (section.iconOffsetX or 0) + 1, (section.iconOffsetY or 0) - 1)
      pushed:SetVertexColor(0.85, 0.85, 0.85, 0.9)
      button:SetPushedTexture(pushed)

      local highlight = button:CreateTexture(nil, "HIGHLIGHT", nil, 0)
      highlight:SetAllPoints()
      highlight:SetColorTexture(1, 1, 1, 0.08)
      button:SetHighlightTexture(highlight)

      button:SetScript("OnEnter", function()
        GameTooltip:SetOwner(button, "ANCHOR_NONE")
        GameTooltip:ClearAllPoints()
        GameTooltip:SetPoint("LEFT", button, "RIGHT", 4, 0)
        GameTooltip:SetText(button.tooltipText, 1, 1, 1, 1)
        GameTooltip:Show()
      end)
      button:SetScript("OnLeave", function()
        MDT:ToggleToolbarTooltip(false)
      end)
      button:SetScript("OnClick", function()
        MDT:SetCurrentSection(section.key)
      end)

      frame.navigationSidebar.buttons[section.key] = button
    end
  end

  frame.navigationSidebar:ClearAllPoints()
  frame.navigationSidebar:SetWidth(navigationSidebarWidth)
  frame.navigationSidebar:SetPoint("TOPRIGHT", frame, "TOPLEFT", 0, panelHeight)
  frame.navigationSidebar:SetPoint("BOTTOMRIGHT", frame, "BOTTOMLEFT")
end

function MDT:MakeSectionFrames(frame)
  frame.sectionContentFrames = frame.sectionContentFrames or {}
  frame.sectionSidePanelFrames = frame.sectionSidePanelFrames or {}

  for _, section in ipairs(MDT:GetNavigationSections()) do
    local sectionKey = section.key
    if section.createContentFrame and not frame.sectionContentFrames[sectionKey] then
      local contentFrame = CreateFrame("Frame", "MDT"..sectionKey.."SectionContentFrame", frame)
      contentFrame:SetAllPoints(frame)
      contentFrame:SetFrameStrata(mainFrameStrata)
      contentFrame:SetFrameLevel(2)
      MDT:RegisterMainFrameDragHandle(contentFrame, frame)
      contentFrame:Hide()
      frame.sectionContentFrames[sectionKey] = contentFrame
    end

    if section.createSidePanelFrame and not frame.sectionSidePanelFrames[sectionKey] then
      local sidePanelFrame = CreateFrame("Frame", "MDT"..sectionKey.."SectionSidePanelFrame", frame.sidePanel)
      sidePanelFrame:SetAllPoints(frame.sidePanel)
      sidePanelFrame:SetFrameStrata(mainFrameStrata)
      sidePanelFrame:SetFrameLevel(3)
      MDT:RegisterMainFrameDragHandle(sidePanelFrame, frame)
      sidePanelFrame:Hide()
      frame.sectionSidePanelFrames[sectionKey] = sidePanelFrame
    end
  end
end
