local ADDON_NAME, ns = ...

-- unify namespace table (avoids split ns tables)
ns = _G[ADDON_NAME] or ns
_G[ADDON_NAME] = ns

-- Backwards compatible exports:
-- old code expects ns.BaseColorsUI:ToggleFrame()
-- new code can use ns.basecolors_ui:Toggle()
ns.BaseColorsUI   = ns.BaseColorsUI or {}
ns.basecolors_ui  = ns.basecolors_ui or ns.BaseColorsUI

local UI = ns.BaseColorsUI

-- =============================================================
-- pom_base_colors_ui.lua
-- Base colors settings (NOT threat) in its own window
-- Backwards compatible API: ToggleFrame()
-- Modern color picker: SetupColorPickerAndShow()
--
-- RULE:
--   UI must be READ-ONLY except when user clicks (pick/reset).
--   Defaults + migrations are owned by InitDB() in pom.lua.
--
-- NOTE:
--   POM now resolves style and color separately internally.
--   This UI edits the compatible base color buckets with modern names,
--   while still reading/writing legacy keys during transition.
-- =============================================================

local DEFAULTS = {
    normal      = { r=0.8, g=0.8, b=0.8, a=1 },
    plusOne     = { r=1.0, g=0.5, b=0.0, a=1 },
    boss        = { r=0.8, g=0.0, b=1.0, a=1 },
    eliteCaster = { r=1.0, g=0.4, b=0.8, a=1 },
    eliteMelee  = { r=0.0, g=0.6, b=1.0, a=1 },

    -- legacy compatibility during transition
    highlevel   = { r=0.8, g=0.0, b=1.0, a=1 },
    caster      = { r=1.0, g=0.4, b=0.8, a=1 },
    melee       = { r=0.0, g=0.6, b=1.0, a=1 },

    neutral     = { r=1.0, g=0.82, b=0.0, a=1 },
}

local ORDER = {
    { key="normal",      label="Normal" },
    { key="boss",        label="Boss / Highlevel" },
    { key="plusOne",     label="Mini boss" },
    { key="eliteCaster", label="Elite Caster Style" },
    { key="eliteMelee",  label="Elite Melee Style" },
    { key="neutral",     label="Neutral (Reaction=4 lock)" },
}

local LEGACY_TO_MODERN = {
    highlevel = "boss",
    caster    = "eliteCaster",
    melee     = "eliteMelee",
}

local MODERN_TO_LEGACY = {
    boss        = "highlevel",
    eliteCaster = "caster",
    eliteMelee  = "melee",
}

-- -------------------------------------------------------------
-- DB helpers
-- -------------------------------------------------------------
local function GetDB()
    if not PlateOMaticDB then return nil end
    if type(PlateOMaticDB.baseColors) ~= "table" then return nil end
    return PlateOMaticDB.baseColors
end

local function ClampColor(c, fallback)
    fallback = fallback or { r=1, g=1, b=1, a=1 }
    if type(c) ~= "table" then c = fallback end
    return {
        r = tonumber(c.r) or fallback.r or 1,
        g = tonumber(c.g) or fallback.g or 1,
        b = tonumber(c.b) or fallback.b or 1,
        a = tonumber(c.a) or fallback.a or 1,
    }
end

local function GetColorReadOnly(key)
    local bdb = GetDB()
    local d = DEFAULTS[key] or { r=1, g=1, b=1, a=1 }

    if not bdb then
        return ClampColor(d, d)
    end

    local legacyKey = MODERN_TO_LEGACY[key]
    local c = bdb[key]
    if type(c) ~= "table" and legacyKey then
        c = bdb[legacyKey]
    end
    if type(c) ~= "table" then
        c = d
    end

    return ClampColor(c, d)
end

-- Write helper: create key ONLY when user actually edits
local function GetOrCreateColor(key)
    if not PlateOMaticDB then return nil end
    PlateOMaticDB.baseColors = PlateOMaticDB.baseColors or {}
    local bdb = PlateOMaticDB.baseColors

    local legacyKey = MODERN_TO_LEGACY[key]
    local source = bdb[key]
    if type(source) ~= "table" and legacyKey then
        source = bdb[legacyKey]
    end

    if type(source) ~= "table" then
        source = DEFAULTS[key] or { r=1, g=1, b=1, a=1 }
    end

    if type(bdb[key]) ~= "table" then
        bdb[key] = {
            r = source.r,
            g = source.g,
            b = source.b,
            a = source.a,
        }
    end

    if legacyKey and type(bdb[legacyKey]) ~= "table" then
        bdb[legacyKey] = {
            r = source.r,
            g = source.g,
            b = source.b,
            a = source.a,
        }
    end

    return bdb[key], legacyKey and bdb[legacyKey] or nil
end

local function WriteColor(key, r, g, b, a)
    local modern, legacy = GetOrCreateColor(key)
    if modern then
        modern.r, modern.g, modern.b, modern.a = r, g, b, a
    end
    if legacy then
        legacy.r, legacy.g, legacy.b, legacy.a = r, g, b, a
    end
end

local function ApplyAll(applyAll)
    if applyAll then
        applyAll()
    end
end

local function MakeTitle(parent, text)
    local t = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
    t:SetPoint("TOPLEFT", 12, -10)
    t:SetText(text)
    return t
end

local function MakeSubtitle(parent, text, anchor)
    local t = parent:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    t:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -4)
    t:SetWidth(384)
    t:SetJustifyH("LEFT")
    t:SetJustifyV("TOP")
    t:SetText(text)
    return t
end

local function MakeColorRow(parent, label, key, y, applyAll)
    local row = CreateFrame("Frame", nil, parent)
    row:SetSize(360, 22)
    row:SetPoint("TOPLEFT", 12, y)

    local txt = row:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    txt:SetPoint("LEFT")
    txt:SetText(label)

    local btn = CreateFrame("Button", nil, row)
    btn:SetSize(18, 18)
    btn:SetPoint("RIGHT", -12, 0)

    local bg = btn:CreateTexture(nil, "BACKGROUND")
    bg:SetAllPoints()
    bg:SetColorTexture(0.15, 0.15, 0.15, 1)

    local sw = btn:CreateTexture(nil, "OVERLAY")
    sw:SetPoint("TOPLEFT", 1, -1)
    sw:SetPoint("BOTTOMRIGHT", -1, 1)

    local function refresh()
        local c = GetColorReadOnly(key)
        sw:SetColorTexture(c.r, c.g, c.b, c.a or 1)
    end
    refresh()

    btn:SetScript("OnClick", function()
        local c0 = GetColorReadOnly(key)

        ColorPickerFrame:SetupColorPickerAndShow({
            r = c0.r,
            g = c0.g,
            b = c0.b,
            opacity = 1 - (c0.a or 1),
            hasOpacity = true,

            swatchFunc = function()
                local r, g, b = ColorPickerFrame:GetColorRGB()
                local a = 1 - (ColorPickerFrame:GetColorAlpha() or 0)

                WriteColor(key, r, g, b, a)
                refresh()
                ApplyAll(applyAll)
            end,

            opacityFunc = function()
                local r, g, b = ColorPickerFrame:GetColorRGB()
                local a = 1 - (ColorPickerFrame:GetColorAlpha() or 0)

                WriteColor(key, r, g, b, a)
                refresh()
                ApplyAll(applyAll)
            end,

            cancelFunc = function(prev)
                if prev then
                    local a = 1 - (prev.opacity or 0)
                    WriteColor(key, prev.r, prev.g, prev.b, a)
                end
                refresh()
                ApplyAll(applyAll)
            end,
        })
    end)

    return refresh
end

function UI:BuildFrame(applyAll)
    local f = CreateFrame("Frame", "POM_BaseColorsFrame", UIParent, "BasicFrameTemplateWithInset")
    f:SetSize(420, 350)
    f:SetPoint("CENTER")
    f:SetFrameStrata("DIALOG")
    f:SetMovable(true)
    f:EnableMouse(true)
    f:RegisterForDrag("LeftButton")
    f:SetScript("OnDragStart", f.StartMoving)
    f:SetScript("OnDragStop", f.StopMovingOrSizing)

    if f.TitleText then
        f.TitleText:SetText("POM - Base Colors")
    end

    local title = MakeTitle(f, "Base Colors")
    MakeSubtitle(
        f,
        "These colors control the non-threat base color buckets. POM now resolves style and color separately internally, and this window uses the new names while still keeping old database keys in sync during transition.",
        title
    )

    f._refreshers = {}

    local y = -82
    for _, it in ipairs(ORDER) do
        local ref = MakeColorRow(f, it.label, it.key, y, applyAll)
        f._refreshers[#f._refreshers + 1] = ref
        y = y - 26
    end

    local reset = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    reset:SetSize(180, 22)
    reset:SetPoint("BOTTOMLEFT", 12, 10)
    reset:SetText("Reset Defaults")
    reset:SetScript("OnClick", function()
        if not PlateOMaticDB then return end
        PlateOMaticDB.baseColors = PlateOMaticDB.baseColors or {}
        local bdb = PlateOMaticDB.baseColors

        for k, v in pairs(DEFAULTS) do
            bdb[k] = { r = v.r, g = v.g, b = v.b, a = v.a }
        end

        -- make sure modern reset also updates legacy aliases explicitly
        for modernKey, legacyKey in pairs(MODERN_TO_LEGACY) do
            local src = bdb[modernKey]
            if src then
                bdb[legacyKey] = { r = src.r, g = src.g, b = src.b, a = src.a }
            end
        end

        if f._refreshers then
            for _, fn in ipairs(f._refreshers) do
                if fn then fn() end
            end
        end

        ApplyAll(applyAll)
    end)

    local close = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
    close:SetSize(120, 22)
    close:SetPoint("BOTTOMRIGHT", -12, 10)
    close:SetText("Close")
    close:SetScript("OnClick", function()
        f:Hide()
    end)

    return f
end

-- New API
function UI:Toggle(applyAll)
    if self._frame and self._frame:IsShown() then
        self._frame:Hide()
        return
    end
    if not self._frame then
        -- NO EnsureDB() here. InitDB owns defaults+migrations.
        self._frame = self:BuildFrame(applyAll)
    end

    if self._frame._refreshers then
        for _, fn in ipairs(self._frame._refreshers) do
            if fn then fn() end
        end
    end

    self._frame:Show()
end

-- Old API (compat)
function UI:ToggleFrame(applyAll)
    self:Toggle(applyAll)
end

-- also expose through ns.basecolors_ui
ns.basecolors_ui = UI