-- HDG_HT_Picker.lua
-- Slide-down customise panel: enable checkbox, width 3-button toggle, ↑↓
-- reorder per widget. Mutates HDG_DB.houseTab.{enabled, order, width} and
-- notifies the parent to re-render.

local _, privateDB = ...
privateDB.HDG_HT = privateDB.HDG_HT or {}
local Picker = {}
privateDB.HDG_HT.Picker = Picker
local LayoutStore = privateDB.HDG_HT.LayoutStore

local HDG_HT = privateDB.HDG_HT
local panel = nil
local rowFrames = {}
local _onChange = nil

local ROW_HEIGHT  = 24
local ROW_GAP     = 2
local PANEL_PAD   = 10
local HEADER_H    = 24
local FOOTER_H    = 50
local COLUMNS     = 1
local COL_GAP     = 14
local PANEL_WIDTH = 360

local function GetScheme()
    local HDG = _G.HousingDecorGuide
    return (HDG and HDG.Theme and HDG.Theme.GetCurrentScheme()) or {
        bg       = { r = 0.04, g = 0.05, b = 0.07 },
        panel    = { r = 0.07, g = 0.08, b = 0.10 },
        border   = { r = 0.30, g = 0.35, b = 0.40 },
        text     = { r = 1, g = 1, b = 1 },
        text_dim = { r = 0.65, g = 0.65, b = 0.70 },
        accent   = { r = 0.90, g = 0.75, b = 0.30 },
        success  = { r = 0.40, g = 0.80, b = 0.45 },
    }
end

local function ApplyFont(fs, ftype)
    local HDG = _G.HousingDecorGuide
    if HDG and HDG.Theme and HDG.Theme.ApplyFont then
        HDG.Theme.ApplyFont(fs, GetScheme(), ftype or "small")
    end
end

local function GetSV()
    HDG_DB = HDG_DB or {}
    HDG_DB.houseTab = HDG_DB.houseTab or {}
    return HDG_DB.houseTab
end

-- Build id → title from privateDB.HDG_HT.Widgets so the picker shows friendly
-- names ("Top $/Lumber") instead of raw camelCase ids ("goblinTopLumber").
-- ID-to-display-name fallback for widgets whose .title is blank or missing.
-- Empty strings are truthy in Lua so a plain `or` doesn't catch them.
local PRETTY_FALLBACK = {}
local function BuildTitleMap()
    local map = {}
    for _, w in pairs(HDG_HT.Widgets or {}) do
        if w.id then
            local t = w.title
            if t == nil or t == "" then t = PRETTY_FALLBACK[w.id] or w.id end
            map[w.id] = t
        end
    end
    return map
end

local function GetDefaultOrderIDs()
    local cfg = HDG_HT.LayoutConfig
    local list = {}
    for id, spec in pairs(cfg.widgets) do
        list[#list + 1] = { id = id, order = spec.order or 999 }
    end
    table.sort(list, function(a, b)
        if a.order ~= b.order then return a.order < b.order end
        return a.id < b.id
    end)
    local ids = {}
    for i, e in ipairs(list) do ids[i] = e.id end
    return ids
end

local function GetEffectiveOrder()
    local sv = GetSV()
    if sv.order and #sv.order > 0 then
        local copy, seen = {}, {}
        for i, id in ipairs(sv.order) do copy[i] = id; seen[id] = true end
        for _, id in ipairs(GetDefaultOrderIDs()) do
            if not seen[id] then copy[#copy + 1] = id end
        end
        return copy
    end
    return GetDefaultOrderIDs()
end

local function SetOrder(newOrder)
    LayoutStore.SetOrder(newOrder)
end

local function MoveID(id, delta)
    local order = GetEffectiveOrder()
    for i, oid in ipairs(order) do
        if oid == id then
            local j = i + delta
            if j < 1 or j > #order then return end
            order[i], order[j] = order[j], order[i]
            SetOrder(order)
            return true
        end
    end
end

local function SetEnabled(id, enabled)
    LayoutStore.SetEnabled(id, enabled)
end

local function SetWidth(id, width)
    LayoutStore.SetWidth(id, width)
end

local function ClearRows()
    for _, r in pairs(rowFrames) do r:Hide(); r:SetParent(nil) end
    rowFrames = {}
end

-- ============================================================================
-- Compact themed pill button (used for width 1/3 / 2/3 / Full toggle)
-- ============================================================================
local function CreatePill(parent, label, w, h, isActive)
    local btn = CreateFrame("Button", nil, parent, "BackdropTemplate")
    btn:SetSize(w, h)
    btn:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 1,
    })
    btn.text = btn:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    btn.text:SetPoint("CENTER", btn, "CENTER", 0, 0)
    btn.text:SetText(label)
    ApplyFont(btn.text, "small")

    function btn:_paint(active)
        local sch = GetScheme()
        if active then
            btn:SetBackdropColor(sch.accent.r * 0.6, sch.accent.g * 0.6, sch.accent.b * 0.6, 0.9)
            btn:SetBackdropBorderColor(sch.accent.r, sch.accent.g, sch.accent.b, 1)
            btn.text:SetTextColor(sch.text.r, sch.text.g, sch.text.b)
        else
            btn:SetBackdropColor(sch.panel.r, sch.panel.g, sch.panel.b, 0.6)
            btn:SetBackdropBorderColor(sch.border.r, sch.border.g, sch.border.b, 0.4)
            btn.text:SetTextColor(sch.text_dim.r, sch.text_dim.g, sch.text_dim.b)
        end
    end
    btn:_paint(isActive)
    btn:SetScript("OnEnter", function(self)
        if not self._active then
            local sch = GetScheme()
            self:SetBackdropBorderColor(sch.accent.r, sch.accent.g, sch.accent.b, 0.7)
        end
    end)
    btn:SetScript("OnLeave", function(self) self:_paint(self._active) end)
    return btn
end

-- ============================================================================
-- Arrow button (chevron up/down) — uses Blizzard's chat scrollbar arrow atlas
-- ============================================================================
local function CreateArrow(parent, dir)
    local btn = CreateFrame("Button", nil, parent)
    btn:SetSize(16, 16)
    btn.tex = btn:CreateTexture(nil, "ARTWORK")
    btn.tex:SetSize(16, 16)
    btn.tex:SetPoint("CENTER")
    -- common-icon-forwardarrow points RIGHT — rotate to up/down.
    btn.tex:SetAtlas("common-icon-forwardarrow")
    if dir == "up" then
        btn.tex:SetRotation(math.pi / 2)   -- 90° CCW → points up
    else
        btn.tex:SetRotation(-math.pi / 2)  -- 90° CW → points down
    end
    btn.tex:SetAlpha(0.7)
    btn:SetScript("OnEnter", function(self) self.tex:SetAlpha(1) end)
    btn:SetScript("OnLeave", function(self) self.tex:SetAlpha(0.7) end)
    return btn
end

-- ============================================================================
-- Row factory
-- ============================================================================
local function CreateRow(parent, id, xOffset, yOffset, rowWidth, titleMap)
    local sch = GetScheme()
    local row = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    row:SetSize(rowWidth, ROW_HEIGHT)
    row:SetPoint("TOPLEFT", parent, "TOPLEFT", xOffset, yOffset)

    -- Subtle row backdrop (zebra-style: barely visible alt tint)
    row:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
    })
    row:SetBackdropColor(sch.panel.r, sch.panel.g, sch.panel.b, 0.25)

    local sv   = GetSV()
    local spec = HDG_HT.LayoutConfig.widgets[id] or {}
    local svEnabled = sv.enabled and sv.enabled[id]
    local enabled
    if svEnabled ~= nil then
        enabled = svEnabled ~= false
    else
        enabled = spec.defaultEnabled ~= false
    end
    local widthOv = (sv.width and sv.width[id]) or spec.width

    -- Checkbox (Blizzard built-in for consistency)
    local cb = CreateFrame("CheckButton", nil, row, "UICheckButtonTemplate")
    cb:SetSize(20, 20)
    cb:SetPoint("LEFT", row, "LEFT", 4, 0)
    cb:SetChecked(enabled)
    cb:SetScript("OnClick", function(self)
        SetEnabled(id, self:GetChecked() and true or false)
        if _onChange then _onChange() end
    end)

    -- Title label (friendly name from widget.title, fallback to id)
    local label = row:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
    label:SetPoint("LEFT", cb, "RIGHT", 4, 0)
    label:SetText(titleMap[id] or id)
    label:SetWidth(120)
    label:SetJustifyH("LEFT")
    label:SetWordWrap(false)
    if enabled then
        label:SetTextColor(sch.text.r, sch.text.g, sch.text.b)
    else
        label:SetTextColor(sch.text_dim.r, sch.text_dim.g, sch.text_dim.b)
    end
    ApplyFont(label, "body")

    -- Width 3-button compact pill toggle
    local widthBtns = {}
    local widthChoices = { "third", "twoThirds", "full" }
    local widthLabels  = { "1/3", "2/3", "Full" }
    for i, choice in ipairs(widthChoices) do
        local isActive = (choice == widthOv)
        local btn = CreatePill(row, widthLabels[i], 36, 18, isActive)
        btn._active = isActive
        if i == 1 then
            btn:SetPoint("LEFT", label, "RIGHT", 8, 0)
        else
            btn:SetPoint("LEFT", widthBtns[i - 1], "RIGHT", 2, 0)
        end
        btn:SetScript("OnClick", function()
            for _, b in ipairs(widthBtns) do b._active = false; b:_paint(false) end
            btn._active = true; btn:_paint(true)
            SetWidth(id, choice)
            if _onChange then _onChange() end
        end)
        widthBtns[i] = btn
    end

    -- Up/Down chevron buttons
    local upBtn = CreateArrow(row, "up")
    upBtn:SetPoint("LEFT", widthBtns[3], "RIGHT", 8, 0)
    upBtn:SetScript("OnClick", function()
        if MoveID(id, -1) and _onChange then _onChange() end
    end)

    local dnBtn = CreateArrow(row, "down")
    dnBtn:SetPoint("LEFT", upBtn, "RIGHT", 1, 0)
    dnBtn:SetScript("OnClick", function()
        if MoveID(id, 1) and _onChange then _onChange() end
    end)

    return row
end

function Picker.Render()
    if not panel then return end
    ClearRows()
    local order = GetEffectiveOrder()
    local titleMap = BuildTitleMap()

    -- Filter to widgets that exist in LAYOUT_CONFIG (skip stale SV ids)
    local visible = {}
    for _, id in ipairs(order) do
        if HDG_HT.LayoutConfig.widgets[id] then visible[#visible + 1] = id end
    end

    local panelW    = panel:GetWidth()
    local rowWidth  = math.floor((panelW - PANEL_PAD * 2 - COL_GAP * (COLUMNS - 1)) / COLUMNS)
    local perCol    = math.ceil(#visible / COLUMNS)
    local listTop   = -PANEL_PAD - HEADER_H

    for i, id in ipairs(visible) do
        local col = math.floor((i - 1) / perCol)
        local idx = (i - 1) - col * perCol
        local x = PANEL_PAD + col * (rowWidth + COL_GAP)
        local y = listTop - idx * (ROW_HEIGHT + ROW_GAP)
        local row = CreateRow(panel, id, x, y, rowWidth, titleMap)
        rowFrames[id] = row
    end

    local height = PANEL_PAD + HEADER_H + perCol * (ROW_HEIGHT + ROW_GAP) - ROW_GAP + PANEL_PAD + FOOTER_H
    panel:SetHeight(height)
end

-- Mounts the picker as a child of `host`. `onChange` is called whenever the
-- user mutates the saved overrides.
function Picker.Mount(host, onChange)
    _onChange = onChange
    if panel then
        panel:Show()
        Picker.Render()
        return
    end

    local sch = GetScheme()
    -- Parent to the host's top-level frame (the HDG main frame) so we can
    -- anchor higher than the host content area — picker top should sit
    -- alongside the addon title bar, not below the tab strip.
    local parentFrame = host
    while parentFrame and parentFrame:GetParent() and parentFrame:GetParent() ~= UIParent do
        parentFrame = parentFrame:GetParent()
    end
    parentFrame = parentFrame or host
    panel = CreateFrame("Frame", nil, parentFrame, "BackdropTemplate")
    panel:SetSize(PANEL_WIDTH, 100)
    -- Pin to RIGHT side of the main frame, top-aligned with its top edge.
    panel:SetPoint("TOPLEFT", parentFrame, "TOPRIGHT", 4, 0)
    panel:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Tooltips\\UI-Tooltip-Border",
        edgeSize = 12,
        insets   = { left = 4, right = 4, top = 4, bottom = 4 },
    })
    panel:SetBackdropColor(sch.bg.r, sch.bg.g, sch.bg.b, 0.97)
    panel:SetBackdropBorderColor(sch.border.r, sch.border.g, sch.border.b, 1)
    panel:SetFrameStrata("DIALOG")
    panel:SetFrameLevel(host:GetFrameLevel() + 5)

    -- Header: "Customise Layout" + accent bar underneath
    local header = panel:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
    header:SetPoint("TOPLEFT", panel, "TOPLEFT", PANEL_PAD, -PANEL_PAD)
    header:SetText("Customise Layout")
    header:SetTextColor(sch.accent.r, sch.accent.g, sch.accent.b)
    ApplyFont(header, "header")

    local accentBar = panel:CreateTexture(nil, "ARTWORK")
    accentBar:SetTexture("Interface\\Buttons\\WHITE8x8")
    accentBar:SetVertexColor(sch.accent.r, sch.accent.g, sch.accent.b, 0.6)
    accentBar:SetHeight(1)
    accentBar:SetPoint("TOPLEFT",  panel, "TOPLEFT",  PANEL_PAD,  -PANEL_PAD - HEADER_H + 4)
    accentBar:SetPoint("TOPRIGHT", panel, "TOPRIGHT", -PANEL_PAD, -PANEL_PAD - HEADER_H + 4)

    -- Reset button (bottom-right)
    local reset = CreateFrame("Button", nil, panel, "BackdropTemplate")
    reset:SetSize(120, 22)
    reset:SetPoint("BOTTOMRIGHT", panel, "BOTTOMRIGHT", -PANEL_PAD, PANEL_PAD)

    -- Hint sits above the reset button so it has room to breathe in the
    -- narrower drawer width.
    local hint = panel:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
    hint:SetPoint("BOTTOMLEFT", panel, "BOTTOMLEFT", PANEL_PAD, PANEL_PAD + 26)
    hint:SetPoint("BOTTOMRIGHT", panel, "BOTTOMRIGHT", -PANEL_PAD, PANEL_PAD + 26)
    hint:SetJustifyH("CENTER")
    hint:SetText("Tick to show. Pick width. Arrows reorder.")
    hint:SetTextColor(sch.text_dim.r, sch.text_dim.g, sch.text_dim.b)
    ApplyFont(hint, "small")
    reset:SetBackdrop({
        bgFile = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 1,
    })
    reset:SetBackdropColor(sch.panel.r, sch.panel.g, sch.panel.b, 0.6)
    reset:SetBackdropBorderColor(sch.border.r, sch.border.g, sch.border.b, 0.5)
    reset.text = reset:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    reset.text:SetPoint("CENTER", reset, "CENTER", 0, 0)
    reset.text:SetText("Reset to default")
    reset.text:SetTextColor(sch.text.r, sch.text.g, sch.text.b)
    ApplyFont(reset.text, "small")
    reset:SetScript("OnEnter", function(self)
        local s = GetScheme()
        self:SetBackdropBorderColor(s.accent.r, s.accent.g, s.accent.b, 0.8)
    end)
    reset:SetScript("OnLeave", function(self)
        local s = GetScheme()
        self:SetBackdropBorderColor(s.border.r, s.border.g, s.border.b, 0.5)
    end)
    reset:SetScript("OnClick", function()
        LayoutStore.ResetAll()
        Picker.Render()
        if _onChange then _onChange() end
    end)

    Picker.Render()
end

function Picker.Hide()
    if panel then panel:Hide() end
end

function Picker.IsShown()
    return panel and panel:IsShown()
end

function Picker.Toggle(host, onChange)
    if Picker.IsShown() then
        Picker.Hide()
    else
        Picker.Mount(host, onChange)
    end
end
