--[[--------------------------------------------------------------------
  PaladinHolyPower – ui/edit_handle.lua
  Universal Movable Edit Handle Panel + Grid Overlay (Edit Mode)

  Edit Mode preview policy (no idle timers):
    • Toggling Edit Mode only sets PHP.EditModeActive and re-evaluates visibility.
    • No hard force-show here; actual visibility is decided by each module’s
      (combat OR preview) rule (HP Bar matches HP Log).
----------------------------------------------------------------------]]

local PHP = _G.PaladinHolyPower
if not PHP then return end

PHP.EditHandle = PHP.EditHandle or {}

-- ======= CONFIG =======
local GRID_SIZE    = 40
local GRID_COLOR   = {0.15, 0.15, 0.15, 0.6}
local BOX_COLOR    = {0.949, 0.902, 0.600, 0.35} -- #F2E699 with 35% alpha
local PANEL_COLOR  = {0.157, 0.157, 0.157, 0.6}
local BORDER_COLOR = {0.1, 0.1, 0.1, 1}
local TITLE_COLOR  = {1, 1, 1, 1}
local RESET_COLOR  = {1, 1, 1, 1}
local EDITBOX_BG   = PANEL_COLOR

-- Match settings panel background exactly (no extra alpha or border)
local PANEL_TEX   = (PHP.Theme and PHP.Theme.Texture and PHP.Theme.Texture())
                 or "Interface\\AddOns\\PaladinHolyPower\\media\\icons\\background\\panel_1.png"
local TINT_CONTENT= { 0.95, 0.90, 0.55, 0.70 } -- from panel.lua

local EditHandles, EditGrid = {}, nil
local CurrentlyOpenHandle = nil

------------------------------------------------------------------------
-- UTILS
------------------------------------------------------------------------

local function SetTextColor(fs, color)
  if fs and color then fs:SetTextColor(unpack(color)) end
end

local function MakeBorder(frame, color, bgFile)
  frame:SetBackdrop({
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    edgeSize = 1,
    bgFile   = bgFile or "Interface\\Buttons\\WHITE8x8"
  })
  frame:SetBackdropColor(unpack(color or PANEL_COLOR))
  frame:SetBackdropBorderColor(unpack(BORDER_COLOR))
end

local function GetXY(settings)
  if type(settings) == "function" then settings = settings() end
  return math.floor(settings.x or 0), math.floor(settings.y or 0)
end

local function CreateLabeledEditBox(parent, labelText, labelFont, boxWidth, boxHeight, boxColor, onEdit)
  local label = parent:CreateFontString(nil, "OVERLAY", labelFont)
  label:SetText(labelText)
  SetTextColor(label, TITLE_COLOR)

  local edit = CreateFrame("EditBox", nil, parent, "BackdropTemplate")
  edit:SetSize(boxWidth, boxHeight)
  edit:SetFontObject(labelFont)
  edit:SetJustifyH("LEFT")
  edit:SetBackdrop({
    bgFile = "Interface\\Buttons\\WHITE8x8",
    edgeFile = "Interface\\Buttons\\WHITE8x8",
    edgeSize = 1
  })
  edit:SetBackdropColor(unpack(BOX_COLOR))
  edit:SetBackdropBorderColor(0, 0, 0, 1)
  edit:SetTextColor(1,1,1,1)
  edit:SetAutoFocus(false)
  if onEdit then
    edit:SetScript("OnEnterPressed", onEdit)
    edit:SetScript("OnEditFocusLost", onEdit)
  end

  return label, edit
end

------------------------------------------------------------------------
-- MAIN EDIT HANDLE PANEL ATTACH API
------------------------------------------------------------------------

function PHP.EditHandle.HideAllHandles()
  for _, h in ipairs(EditHandles) do
    if h then h:Hide() end
  end
  CurrentlyOpenHandle = nil
end

function PHP.EditHandle.ShowAllHighlightBoxes()
  for _, h in ipairs(EditHandles) do
    if h and h.target and h.target._editBox then
      h.target._editBox:Show()
    end
  end
end

function PHP.EditHandle.HideAllHighlightBoxes()
  for _, h in ipairs(EditHandles) do
    if h and h.target and h.target._editBox then
      h.target._editBox:Hide()
    end
  end
end

function PHP.EditHandle.AttachMovablePanel(target, settingsArg, opts)
  if not target then return end

  -- Remove any previous handle from this frame
  if target._editHandlePanel then
    target._editHandlePanel:Hide()
    target._editHandlePanel = nil
  end

  local settings   = (type(settingsArg) == "function" and settingsArg) or (function() return settingsArg end)
  local default    = (opts and opts.default) or {x=0, y=0}
  -- accept both opts.panelTitle and opts.title (some callers used "title")
  local panelTitle = (opts and (opts.panelTitle or opts.title)) or "Mover"
  local onChange   = (opts and opts.onChange) or function() end

  -- Highlight box overlay on the target (yellow frame, always visible in edit mode)
  if not target._editBox then
    local box = CreateFrame("Frame", nil, target)
    box:SetAllPoints(target)
    box:SetFrameStrata("HIGH")
    box:SetFrameLevel(target:GetFrameLevel() + 30)
    box.bg = box:CreateTexture(nil, "OVERLAY", nil, 1)
    box.bg:SetAllPoints(box)
    box.bg:SetColorTexture(unpack(BOX_COLOR))
    local border = CreateFrame("Frame", nil, box, "BackdropTemplate")
    border:SetAllPoints(box)
    border:SetBackdrop({
      edgeFile = "Interface\\Buttons\\WHITE8x8", edgeSize = 1,
      insets = { left = 0, right = 0, top = 0, bottom = 0 }
    })
    border:SetBackdropBorderColor(0.95, 0.85, 0.4, 1)
    border:SetFrameLevel(box:GetFrameLevel() + 1)
    box.border = border
    box:Hide()
    target._editBox = box
  end

  -- Handle Panel (the thing that pops up below the icon)
  local handle = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
  handle:SetSize(180, 110)
  handle:SetFrameStrata("TOOLTIP")
  handle:SetMovable(false)
  handle.target = target
  target._editHandlePanel = handle

  -- Match settings panel content look (no extra alpha, no border)
  handle:SetBackdrop({ bgFile = PANEL_TEX })            -- textured bg
  handle:SetBackdropColor(TINT_CONTENT[1], TINT_CONTENT[2], TINT_CONTENT[3], TINT_CONTENT[4])
  handle:SetBackdropBorderColor(0, 0, 0, 0)             -- no border

  -- Title
  handle.title = handle:CreateFontString(nil, "OVERLAY", "GameFontNormal")
  handle.title:SetPoint("TOP", handle, "TOP", 0, -8)
  handle.title:SetText(panelTitle)
  SetTextColor(handle.title, TITLE_COLOR)

  -- X/Y Value Row
  handle.xyRow = CreateFrame("Frame", nil, handle)
  handle.xyRow:SetSize(170, 24)
  handle.xyRow:SetPoint("TOP", handle, "TOP", 0, -33)

  local labelFont, boxWidth, boxHeight = "GameFontNormal", 36, 18
  local spacing1, spacing2, spacing3 = 3, 18, 3
  local rowSpacing = 5  -- Space between rows (xyRow <-> Reset button)

  -- X Label/Edit
  handle.xLabel, handle.xEdit = CreateLabeledEditBox(handle.xyRow, "X:", labelFont, boxWidth, boxHeight, EDITBOX_BG)
  -- Y Label/Edit
  handle.yLabel, handle.yEdit = CreateLabeledEditBox(handle.xyRow, "Y:", labelFont, boxWidth, boxHeight, EDITBOX_BG)

  -- Position the row
  local totalWidth = handle.xLabel:GetStringWidth() + spacing1 + boxWidth +
                     spacing2 + handle.yLabel:GetStringWidth() + spacing3 + boxWidth
  handle.xyRow:SetWidth(totalWidth)
  handle.xLabel:SetPoint("LEFT", handle.xyRow, "LEFT")
  handle.xEdit:SetPoint("LEFT", handle.xLabel, "RIGHT", spacing1, -1)
  handle.yLabel:SetPoint("LEFT", handle.xEdit, "RIGHT", spacing2, 0)
  handle.yEdit:SetPoint("LEFT", handle.yLabel, "RIGHT", spacing3, -1)

  -- Reset Button (centered and spaced)
  handle.reset = PHP.CreateStyledButton(handle, "Reset", 0, 0, 65, 20, function()
    local S = settings()
    S.x, S.y = default.x or 0, default.y or 0
    target:ClearAllPoints()
    target:SetPoint("CENTER", UIParent, "CENTER", S.x, S.y)
    handle:UpdateXY()
    if target._editBox then target._editBox:SetAllPoints(target) end
    onChange(S.x, S.y, target)
  end)
  handle.reset:ClearAllPoints()
  handle.reset:SetPoint("TOP", handle.xyRow, "BOTTOM", 0, -rowSpacing)

  -- X Edit logic
  local function xEditHandler(self)
    local new = tonumber(self:GetText())
    local S = settings()
    if new then
      S.x = new
      target:ClearAllPoints()
      target:SetPoint("CENTER", UIParent, "CENTER", S.x, S.y or 0)
      if handle.UpdateXY then handle:UpdateXY() end
      if target._editBox then target._editBox:SetAllPoints(target) end
      onChange(S.x, S.y, target)
    else
      handle:UpdateXY()
    end
    self:ClearFocus()
  end
  handle.xEdit:SetScript("OnEnterPressed", xEditHandler)
  handle.xEdit:SetScript("OnEditFocusLost", xEditHandler)

  -- Y Edit logic
  local function yEditHandler(self)
    local new = tonumber(self:GetText())
    local S = settings()
    if new then
      S.y = new
      target:ClearAllPoints()
      target:SetPoint("CENTER", UIParent, "CENTER", S.x or 0, S.y)
      if handle.UpdateXY then handle:UpdateXY() end
      if target._editBox then target._editBox:SetAllPoints(target) end
      onChange(S.x, S.y, target)
    else
      handle:UpdateXY()
    end
    self:ClearFocus()
  end
  handle.yEdit:SetScript("OnEnterPressed", yEditHandler)
  handle.yEdit:SetScript("OnEditFocusLost", yEditHandler)

  function handle:UpdateXY()
    local x, y = GetXY(settings)
    handle.xEdit:SetText(x)
    handle.yEdit:SetText(y)
  end

  -- Nudge Arrows
  local nudgeSize, arrowSpacing, numArrows = 18, 10, 4
  local nudgeRowWidth = nudgeSize * numArrows + arrowSpacing * (numArrows - 1)
  local nudgeSpacingY = 5
  handle.nudgeRow = CreateFrame("Frame", nil, handle)
  handle.nudgeRow:SetSize(nudgeRowWidth, nudgeSize)
  handle.nudgeRow:SetPoint("TOP", handle.reset, "BOTTOM", 0, -nudgeSpacingY)

  local MEDIA_BASE = (PHP and PHP.MEDIA) or "Interface\\AddOns\\PaladinHolyPower\\media\\"
  local arrows = {
    {name="Left",  tex=MEDIA_BASE .. "icons\\assets\\chevron_left.png",  dx=-1, dy=0 },
    {name="Up",    tex=MEDIA_BASE .. "icons\\assets\\chevron_up.png",    dx=0,  dy=1 },
    {name="Down",  tex=MEDIA_BASE .. "icons\\assets\\chevron_down.png",  dx=0,  dy=-1},
    {name="Right", tex=MEDIA_BASE .. "icons\\assets\\chevron_right.png", dx=1,  dy=0 },
  }
  handle.nudges, handle.nudgeRow.buttons = {}, {}
  for i, info in ipairs(arrows) do
    local btn = CreateFrame("Button", nil, handle.nudgeRow)
    btn:SetSize(nudgeSize, nudgeSize)
    btn:SetNormalTexture(info.tex)
    btn:GetNormalTexture():SetVertexColor(1,1,1,1)
    btn:SetPoint("LEFT", i == 1 and handle.nudgeRow or handle.nudgeRow.buttons[i-1], i == 1 and "LEFT" or "RIGHT", i == 1 and 0 or arrowSpacing, 0)
    handle.nudgeRow.buttons[i] = btn
    handle.nudges[info.name] = btn
    btn:SetScript("OnClick", function()
      local step, S = IsShiftKeyDown() and 10 or 1, settings()
      S.x, S.y = (S.x or 0) + info.dx * step, (S.y or 0) + info.dy * step
      target:ClearAllPoints()
      target:SetPoint("CENTER", UIParent, "CENTER", S.x, S.y)
      handle:UpdateXY()
      if target._editBox then target._editBox:SetAllPoints(target) end
      onChange(S.x, S.y, target)
    end)
    btn:SetScript("OnEnter", function(self)
      self:GetNormalTexture():SetVertexColor(0.8, 0.8, 0.8, 1)
    end)
    btn:SetScript("OnLeave", function(self)
      self:GetNormalTexture():SetVertexColor(1, 1, 1, 1)
    end)
  end

  -- Drag and Click logic
  local dragThreshold = 2
  local clickCandidate = false
  local downX, downY

  target:SetMovable(true)
  if not (InCombatLockdown and InCombatLockdown()) then
    target:RegisterForDrag("LeftButton")
  end

  target:SetScript("OnMouseDown", function(self, button)
    if PHP.EditModeActive and button == "LeftButton" then
      clickCandidate = true
      downX, downY = GetCursorPosition()
    end
  end)

  target:SetScript("OnMouseUp", function(self, button)
    if not PHP.EditModeActive or button ~= "LeftButton" then return end
    if clickCandidate then
      local upX, upY = GetCursorPosition()
      local dist = math.sqrt((upX - downX)^2 + (upY - downY)^2)
      if dist < dragThreshold then
        self:ShowEditHandle()
      end
    end
    clickCandidate = false
  end)

  -- Drag logic: live-update edit fields; commit on drag stop
  target:SetScript("OnDragStart", function(self)
    if PHP.EditModeActive then
      self:StartMoving()
      self:SetScript("OnUpdate", function(self)
        if handle and handle:IsShown() then
          local centerX, centerY = UIParent:GetWidth() / 2, UIParent:GetHeight() / 2
          local left = self:GetLeft() + self:GetWidth() / 2
          local bottom = self:GetBottom() + self:GetHeight() / 2
          local x = math.floor(left - centerX)
          local y = math.floor(bottom - centerY)
          handle.xEdit:SetText(x)
          handle.yEdit:SetText(y)
        end
      end)
    end
  end)
  target:SetScript("OnDragStop", function(self)
    self:StopMovingOrSizing()
    self:SetScript("OnUpdate", nil)
    local centerX, centerY = UIParent:GetWidth() / 2, UIParent:GetHeight() / 2
    local left = self:GetLeft() + self:GetWidth() / 2
    local bottom = self:GetBottom() + self:GetHeight() / 2
    local x = math.floor(left - centerX)
    local y = math.floor(bottom - centerY)
    local S = settings()
    S.x, S.y = x, y
    if handle.UpdateXY then handle:UpdateXY() end
    if target._editBox then target._editBox:SetAllPoints(target) end
    onChange(x, y, target)
  end)

  -- Show/hide logic
  handle:SetPoint("TOP", target, "BOTTOM", 0, -5)
  handle:Hide()
  handle:SetScript("OnShow", function()
    handle:UpdateXY()
    if target._editBox then target._editBox:Show() end
    if not (InCombatLockdown and InCombatLockdown()) then
      target:EnableMouse(true)
      target:RegisterForDrag("LeftButton")
    end
    CurrentlyOpenHandle = handle
  end)
  handle:SetScript("OnHide", function()
    if not (InCombatLockdown and InCombatLockdown()) then
      target:RegisterForDrag("LeftButton")
    end
    if CurrentlyOpenHandle == handle then CurrentlyOpenHandle = nil end
  end)

  table.insert(EditHandles, handle)
  target._editHandlePanel = handle

  -- Expose for toggling/edit mode; only one at a time
  target.ShowEditHandle = function()
    if CurrentlyOpenHandle == handle then
      handle:Hide()
      CurrentlyOpenHandle = nil
    else
      if CurrentlyOpenHandle then CurrentlyOpenHandle:Hide() end
      handle:Show()
    end
  end
  target.HideEditHandle = function()
    handle:Hide()
    if CurrentlyOpenHandle == handle then CurrentlyOpenHandle = nil end
  end

  return handle
end

function PHP.EditHandle.Attach(...) return PHP.EditHandle.AttachMovablePanel(...) end

------------------------------------------------------------------------
-- EDIT GRID (background overlay)
------------------------------------------------------------------------

function PHP.ShowEditGrid()
  if EditGrid then EditGrid:Show() return end
  local grid = CreateFrame("Frame", nil, UIParent)
  grid:SetAllPoints(UIParent)
  grid:SetFrameStrata("FULLSCREEN_DIALOG")
  grid.lines = {}
  local w, h = UIParent:GetWidth(), UIParent:GetHeight()
  for x = GRID_SIZE, w, GRID_SIZE do
    local l = grid:CreateTexture(nil, "BACKGROUND")
    l:SetColorTexture(unpack(GRID_COLOR))
    l:SetPoint("TOPLEFT", grid, "TOPLEFT", x, 0)
    l:SetPoint("BOTTOMLEFT", grid, "BOTTOMLEFT", x, 0)
    l:SetWidth(1)
    l:SetAlpha(GRID_COLOR[4])
    table.insert(grid.lines, l)
  end
  for y = GRID_SIZE, h, GRID_SIZE do
    local l = grid:CreateTexture(nil, "BACKGROUND")
    l:SetColorTexture(unpack(GRID_COLOR))
    l:SetPoint("TOPLEFT", grid, "TOPLEFT", 0, -y)
    l:SetPoint("TOPRIGHT", grid, "TOPRIGHT", 0, -y)
    l:SetHeight(1)
    l:SetAlpha(GRID_COLOR[4])
    table.insert(grid.lines, l)
  end
  EditGrid = grid
end

function PHP.HideEditGrid() if EditGrid then EditGrid:Hide() end end
function PHP.ToggleEditGrid()
  if EditGrid and EditGrid:IsShown() then PHP.HideEditGrid() else PHP.ShowEditGrid() end
end

------------------------------------------------------------------------
-- SHOW/HIDE ALL HANDLES + PREVIEW POLICY
------------------------------------------------------------------------

function PHP.ShowAllEditHandles()
  for _, h in ipairs(EditHandles) do
    if h and h.target and h.target._editBox then h.target._editBox:Show() end
    if h and h.target and not (InCombatLockdown and InCombatLockdown()) then h.target:EnableMouse(true) end
    if h then h:Hide() end
  end
  -- Edit Mode ON → set flag and let modules re-evaluate via (combat OR preview)
  PHP.EditModeActive = true
  if PHP.UpdateHPTracker then pcall(PHP.UpdateHPTracker) end
  if PHP._HPL_ApplyVisibility then pcall(PHP._HPL_ApplyVisibility) end
  PHP.ShowEditGrid()
end

function PHP.HideAllEditHandles()
  for _, h in ipairs(EditHandles) do
    if h then h:Hide() end
    if h and h.target and h.target._editBox then h.target._editBox:Hide() end
    if h and h.target and not (InCombatLockdown and InCombatLockdown()) then h.target:EnableMouse(false) end
  end
  -- Edit Mode OFF → clear flag and re-evaluate
  PHP.EditModeActive = false
  if PHP.UpdateHPTracker then pcall(PHP.UpdateHPTracker) end
  if PHP._HPL_ApplyVisibility then pcall(PHP._HPL_ApplyVisibility) end
  PHP.HideEditGrid()
end

function PHP.ToggleEditMode()
  if EditHandles[1] and (EditHandles[1].target and EditHandles[1].target._editBox:IsShown()) then
    -- turning OFF
    PHP.HideAllEditHandles()
  else
    -- turning ON
    PHP.ShowAllEditHandles()
  end
end

-- (Optional) For macro use: /run PHP.ToggleEditMode()
-- No return statement!