-- ============================================================================
-- pomh.lua
-- POM - Nameplate vertical offset settings UI
--
-- Slash:
--   /pomh
--
-- Stores:
--   PlateOMaticDB.nameplateOffsetUI.offset
--
-- Public API:
--   ns.GetNameplateVisualYOffset() -> number
--
-- IMPORTANT:
--   This file only provides the setting + UI + DB + accessor.
--   The actual visual movement must be applied inside POM's own layout code.
-- ============================================================================

local ADDON_NAME, ns = ...

ns = _G[ADDON_NAME] or ns or {}
_G[ADDON_NAME] = ns

local M = CreateFrame("Frame")
ns.POMHeightUI = M

local type = type
local tostring = tostring
local floor = math.floor
local ipairs = ipairs
local pcall = pcall

local DEFAULT_OFFSET = 0
local DB_KEY = "nameplateOffsetUI"

-- ============================================================================
-- DB
-- ============================================================================

local function GetDB()
    _G.PlateOMaticDB = _G.PlateOMaticDB or {}

    local db = _G.PlateOMaticDB[DB_KEY]
    if type(db) ~= "table" then
        db = {}
        _G.PlateOMaticDB[DB_KEY] = db
    end

    if type(db.offset) ~= "number" then
        db.offset = DEFAULT_OFFSET
    end

    return db
end

function ns.GetNameplateVisualYOffset()
    local db = GetDB()
    return db.offset or DEFAULT_OFFSET
end

-- ============================================================================
-- Refresh helper
-- Tries to ask POM to restyle visible nameplates without touching restricted
-- measurement APIs.
-- ============================================================================

local function TryRefreshPlate(plate)
    if not plate then return end

    local mixins = ns.mixins
    if type(mixins) ~= "table" then return end

    -- Try likely apply patterns safely.
    if type(mixins.ApplyLight) == "function" then
        if pcall(mixins.ApplyLight, mixins, plate) then return end
        if pcall(mixins.ApplyLight, plate) then return end
        if plate.UnitFrame and pcall(mixins.ApplyLight, mixins, plate.UnitFrame) then return end
        if plate.UnitFrame and pcall(mixins.ApplyLight, plate.UnitFrame) then return end
    end

    if type(mixins.Apply) == "function" then
        if pcall(mixins.Apply, mixins, plate) then return end
        if pcall(mixins.Apply, plate) then return end
        if plate.UnitFrame and pcall(mixins.Apply, mixins, plate.UnitFrame) then return end
        if plate.UnitFrame and pcall(mixins.Apply, plate.UnitFrame) then return end
    end
end

local function RefreshAllVisible()
    local plates = C_NamePlate.GetNamePlates()
    if not plates then return end

    for i = 1, #plates do
        TryRefreshPlate(plates[i])
    end
end

-- ============================================================================
-- UI
-- ============================================================================

local UI = CreateFrame("Frame", "POMHFrame", UIParent, "BackdropTemplate")
UI:SetSize(340, 190)
UI:SetPoint("CENTER")
UI:SetFrameStrata("DIALOG")
UI:SetClampedToScreen(true)
UI:EnableMouse(true)
UI:SetMovable(true)
UI:RegisterForDrag("LeftButton")
UI:SetScript("OnDragStart", function(self) self:StartMoving() end)
UI:SetScript("OnDragStop", function(self) self:StopMovingOrSizing() end)
UI:Hide()

if UI.SetBackdrop then
    UI:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8X8",
        edgeFile = "Interface\\Buttons\\WHITE8X8",
        edgeSize = 1,
        insets = { left = 0, right = 0, top = 0, bottom = 0 },
    })
    UI:SetBackdropColor(0.05, 0.05, 0.05, 0.96)
    UI:SetBackdropBorderColor(0.20, 0.20, 0.20, 1)
end

local title = UI:CreateFontString(nil, "OVERLAY", "GameFontNormal")
title:SetPoint("TOP", 0, -10)
title:SetText("POM Nameplate Vertical Offset")

local subtitle = UI:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
subtitle:SetPoint("TOP", title, "BOTTOM", 0, -6)
subtitle:SetText("Negative = move plate visuals down")

local valueText = UI:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
valueText:SetPoint("TOP", subtitle, "BOTTOM", 0, -26)
valueText:SetText("Offset: " .. tostring(ns.GetNameplateVisualYOffset()))

local helpText = UI:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
helpText:SetPoint("BOTTOM", 0, 18)
helpText:SetText("Stored in PlateOMaticDB.nameplateOffsetUI.offset")

local slider = CreateFrame("Slider", "POMHOffsetSlider", UI, "OptionsSliderTemplate")
slider:SetPoint("TOP", valueText, "BOTTOM", 0, -22)
slider:SetWidth(230)
slider:SetMinMaxValues(-100, 100)
slider:SetValueStep(1)
slider:SetObeyStepOnDrag(true)

local low = _G[slider:GetName() .. "Low"]
local high = _G[slider:GetName() .. "High"]
local text = _G[slider:GetName() .. "Text"]

if low then low:SetText("-100") end
if high then high:SetText("100") end
if text then text:SetText("Plate Offset") end

slider:SetScript("OnValueChanged", function(self, value)
    value = floor((value or 0) + 0.5)

    local db = GetDB()
    if db.offset == value then
        valueText:SetText("Offset: " .. tostring(value))
        return
    end

    db.offset = value
    valueText:SetText("Offset: " .. tostring(value))
    RefreshAllVisible()
end)

local reset = CreateFrame("Button", nil, UI, "UIPanelButtonTemplate")
reset:SetSize(90, 22)
reset:SetPoint("BOTTOM", 0, 46)
reset:SetText("Reset")
reset:SetScript("OnClick", function()
    local db = GetDB()
    db.offset = DEFAULT_OFFSET
    valueText:SetText("Offset: " .. tostring(DEFAULT_OFFSET))
    slider:SetValue(DEFAULT_OFFSET)
    RefreshAllVisible()
end)

local close = CreateFrame("Button", nil, UI, "UIPanelCloseButton")
close:SetPoint("TOPRIGHT", 1, 1)

local function ToggleUI()
    if UI:IsShown() then
        UI:Hide()
        return
    end

    local db = GetDB()
    UI:Show()
    valueText:SetText("Offset: " .. tostring(db.offset or DEFAULT_OFFSET))
    slider:SetValue(db.offset or DEFAULT_OFFSET)
end

SLASH_POMH1 = "/pomh"
SlashCmdList["POMH"] = ToggleUI

-- ============================================================================
-- Events
-- ============================================================================

M:SetScript("OnEvent", function(_, event, arg1)
    if event == "PLAYER_LOGIN" then
        GetDB()
        RefreshAllVisible()

    elseif event == "NAME_PLATE_UNIT_ADDED" then
        local unit = arg1
        if unit then
            local plate = C_NamePlate.GetNamePlateForUnit(unit)
            if plate then
                TryRefreshPlate(plate)
            end
        end
    end
end)

M:RegisterEvent("PLAYER_LOGIN")
M:RegisterEvent("NAME_PLATE_UNIT_ADDED")