-- Synonyms.lua
-- Works with default, custom (Dialect), and any additional chat-edit boxes.

------------------------------------------------------------------------
--  Data & UI
------------------------------------------------------------------------
local SynonymDB    = SynonymDB or {}
local SynonymsMenu = CreateFrame("Frame", "SynonymsMenu", UIParent, "UIDropDownMenuTemplate")

-- Per-word page tracker
local pageOffsets = {}

------------------------------------------------------------------------
--  Helpers
------------------------------------------------------------------------
-- Pull exactly 20 synonyms at a time
local function FetchSynonyms(key)
  local all  = SynonymDB[key] or {}
  local page = pageOffsets[key] or 1
  local first = (page - 1) * 20 + 1
  local out   = {}
  for i = first, math.min(first + 19, #all) do
    out[#out + 1] = all[i]
  end
  return out
end

-- Total page count for a word
local function NumPages(key)
  local all = SynonymDB[key] or {}
  return math.max(1, math.ceil(#all / 20))
end

-- Word under the cursor in an edit box
local function GetWordUnderCursor(editBox)
  local txt = editBox:GetText() or ""
  local pos = editBox:GetCursorPosition()
  pos = math.min(math.max(pos, 0), #txt)

  local s = pos
  while s > 0 and txt:sub(s, s):match("[%w']") do s = s - 1 end
  local startPos = s + 1

  local e = pos + 1
  while e <= #txt and txt:sub(e, e):match("[%w']") do e = e + 1 end
  local endPos = e - 1

  if startPos > endPos then return nil end
  return txt:sub(startPos, endPos), startPos, endPos
end

------------------------------------------------------------------------
--  Synonym popup
------------------------------------------------------------------------
local currentEditBox, currentWord, currentSPos, currentEPos

local function ShowSynonyms(editBox)
  local word, sPos, ePos = GetWordUnderCursor(editBox)
  if not word then return end

  local key = word:lower()
  if not SynonymDB[key] then return end

  currentEditBox = editBox
  currentWord    = word
  currentSPos    = sPos
  currentEPos    = ePos
  pageOffsets[key] = pageOffsets[key] or 1

  CloseDropDownMenus()

  UIDropDownMenu_Initialize(SynonymsMenu, function(_, level)
    if level ~= 1 then return end

    local key   = currentWord:lower()
    local page  = pageOffsets[key]
    local pages = NumPages(key)
    if page > pages then pageOffsets[key] = 1 end

    local raw = FetchSynonyms(key)
    local cap = currentWord:sub(1, 1):match("%u")

    -- Title
    local info = UIDropDownMenu_CreateInfo()
    info.text          = ("'%s' (page %d/%d)   |cFFFF0000[X]|r"):format(currentWord, page, pages)
    info.notCheckable  = true
    info.func          = CloseDropDownMenus
    UIDropDownMenu_AddButton(info)

    UIDropDownMenu_AddSeparator()

    -- Synonym list
    for _, syn in ipairs(raw) do
      local disp = cap and syn:gsub("^%l", string.upper) or syn
      local opt  = UIDropDownMenu_CreateInfo()
      opt.text         = disp
      opt.notCheckable = true
      opt.func = function()
        local txt    = currentEditBox:GetText()
        local before = txt:sub(1, currentSPos - 1)
        local after  = txt:sub(currentEPos + 1)
        currentEditBox:SetText(before .. disp .. after)
        currentEditBox:SetCursorPosition(#before + #disp)
      end
      UIDropDownMenu_AddButton(opt)
    end

    UIDropDownMenu_AddSeparator()

    -- Pagination
    local nav = UIDropDownMenu_CreateInfo()
    nav.text         = (page < pages) and "Next page" or "Wrap to page 1"
    nav.notCheckable = true
    nav.func = function()
      pageOffsets[key] = (page < pages) and (page + 1) or 1
      C_Timer.After(0.01, function()
        ToggleDropDownMenu(1, nil, SynonymsMenu, "cursor", 0, 0)
      end)
    end
    UIDropDownMenu_AddButton(nav)
  end, "MENU")

  ToggleDropDownMenu(1, nil, SynonymsMenu, "cursor", 0, 0)
end

------------------------------------------------------------------------
--  Public hook helper
------------------------------------------------------------------------
function HookSynonymSupport(editBox)
  if not editBox or editBox.__SynonymsHooked then return end
  editBox.__SynonymsHooked = true

  editBox:HookScript("OnMouseUp", function(self, button)
    if button == "RightButton" and IsShiftKeyDown() then
      ShowSynonyms(self)
    end
  end)
end

------------------------------------------------------------------------
--  Chat-frame integration
------------------------------------------------------------------------
local function HookAllChatEditBoxes()
  for i = 1, NUM_CHAT_WINDOWS do
    local eb = _G["ChatFrame" .. i .. "EditBox"]
    if eb then HookSynonymSupport(eb) end
  end
end

local f = CreateFrame("Frame")
f:RegisterEvent("PLAYER_LOGIN")
f:SetScript("OnEvent", function()
  -- All windows that already exist
  HookAllChatEditBoxes()

  -- Any new permanent windows (/new, “+” tab, etc.)
  hooksecurefunc("FCF_OpenNewWindow", function()
    C_Timer.After(0, HookAllChatEditBoxes)
  end)

  -- Temporary windows (whispers, communities, real-ID, etc.)
  hooksecurefunc("FCF_OpenTemporaryWindow", function()
    C_Timer.After(0, HookAllChatEditBoxes)
  end)

  -- Dialect UI custom box (wait a moment for it to load)
  C_Timer.After(2, function()
    if DialectUI and DialectUI.EditBox then
      HookSynonymSupport(DialectUI.EditBox)
    end
  end)
end)

------------------------------------------------------------------------
--  External API
------------------------------------------------------------------------
function Synonyms_RegisterEditBox(editBox)
  if not editBox then return end
  HookSynonymSupport(editBox)
end
