local PT = AhUI
if not PT then return end
local L = PT.L

local syncingUI = false

local function IP()
    return PT.InfoPanel
end

local function EnsureIPConfig()
    local ip = IP()
    if not ip then return nil end
    if ip.InitConfig then ip:InitConfig() end
    if not ip.config then return nil end

    ip.config.appearance = ip.config.appearance or {}
    ip.config.elements   = ip.config.elements   or {}
    ip.config.layout     = ip.config.layout     or {}
    ip.config.panelPoint = ip.config.panelPoint or { point="TOP", relPoint="TOP", x=0, y=-2 }

    if ip.EnsureLayout then
        ip:EnsureLayout()
    end

    return ip.config
end

function PT.InfoPanel:SyncPositionToUI()
    local xBox = self._posX
    local yBox = self._posY
    if not xBox or not yBox then return end

    local cfg = EnsureIPConfig()
    if not cfg or not cfg.panelPoint then return end

    xBox:SetText(tostring(cfg.panelPoint.x or 0))
    xBox:SetCursorPosition(0)

    yBox:SetText(tostring(cfg.panelPoint.y or 0))
    yBox:SetCursorPosition(0)
end

local function ApplyAll()
    local ip = IP()
    if not ip or not ip.config then return end

    if ip.SetEnabled then
        ip:SetEnabled(ip.config.enabled ~= false)
    elseif ip.frame then
        ip.frame:SetShown(ip.config.enabled ~= false)
    end

    if ip.SetLocked then
        ip:SetLocked(ip.config.locked == true)
    end

    if ip.UpdateAppearance then
        ip:UpdateAppearance()
    end

    if ip.UpdateElements then
        ip:UpdateElements()
    end
end

local f = CreateFrame("Frame", "AhUISettingsInfoPanel", UIParent)
f:SetSize(520, 520)

local title = f:CreateFontString(nil, "OVERLAY", "GameFontHighlightLarge")
title:SetPoint("TOPLEFT", 16, -16)
title:SetText(L["InfoPanel_Title"])

local desc = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
desc:SetPoint("TOPLEFT", title, "BOTTOMLEFT", 0, -8)
desc:SetText(L["InfoPanel_Desc"])

local enable = CreateFrame("CheckButton", nil, f, "UICheckButtonTemplate")
enable:SetPoint("TOPLEFT", desc, "BOTTOMLEFT", 0, -12)
enable.text:SetText(L["InfoPanel_Enable"])

enable:SetScript("OnClick", function(self)
    if syncingUI then return end
    local cfg = EnsureIPConfig()
    if not cfg then return end
    cfg.enabled = self:GetChecked() and true or false
    ApplyAll()
end)

local posLabel = f:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
posLabel:SetPoint("LEFT", enable.text, "RIGHT", 10, 0)
posLabel:SetText("X / Y:")

local posX = CreateFrame("EditBox", nil, f, "InputBoxTemplate")
posX:SetSize(50, 20)
posX:SetPoint("LEFT", posLabel, "RIGHT", 12, 0)
posX:SetAutoFocus(false)
posX:SetMaxLetters(5)
posX:SetJustifyH("CENTER")
posX:SetTextInsets(6, 6, 0, 0)
posX:SetTextColor(1, 1, 1, 1)

local posY = CreateFrame("EditBox", nil, f, "InputBoxTemplate")
posY:SetSize(50, 20)
posY:SetPoint("LEFT", posX, "RIGHT", 30, 0)
posY:SetAutoFocus(false)
posY:SetNumeric(true)
posY:SetMaxLetters(5)
posY:SetJustifyH("CENTER")
posY:SetTextInsets(6, 6, 0, 0)
posY:SetTextColor(1, 1, 1, 1)

PT.InfoPanel._posX = posX
PT.InfoPanel._posY = posY

local function CreatePlainButton(parent, text)
    local b = CreateFrame("Button", nil, parent)
    b:SetSize(14, 14)

    local fs = b:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
    fs:SetAllPoints()
    fs:SetText(text)
    fs:SetJustifyH("CENTER")
    fs:SetJustifyV("MIDDLE")

    b.text = fs
    return b
end
local xPlus  = CreatePlainButton(f, "+")
local xMinus = CreatePlainButton(f, "-")
local yPlus  = CreatePlainButton(f, "+")
local yMinus = CreatePlainButton(f, "-")

xPlus:SetPoint("LEFT", posX, "RIGHT", 2, 2)
xMinus:SetPoint("TOP", xPlus, "BOTTOM", 0, 6)
yPlus:SetPoint("LEFT", posY, "RIGHT", 2, 2)
yMinus:SetPoint("TOP", yPlus, "BOTTOM", 0, 6)

local NudgePanel

local function ApplyPanelPosition()
    local ip = IP()
    if not ip or not ip.frame then return end

    local cfg = EnsureIPConfig()
    if not cfg then return end

    local x = tonumber(posX:GetText()) or 0
    local y = tonumber(posY:GetText()) or 0

    cfg.panelPoint.x = math.floor(x)
    cfg.panelPoint.y = math.floor(y)

ip.frame:ClearAllPoints()
ip.frame:SetPoint("BOTTOM", UIParent, "BOTTOM",
    cfg.panelPoint.x or 0,
    cfg.panelPoint.y or 0
)
end

NudgePanel = function(dx, dy)
    local cfg = EnsureIPConfig()
    if not cfg then return end

    cfg.panelPoint.x = (cfg.panelPoint.x or 0) + (dx or 0)
    cfg.panelPoint.y = (cfg.panelPoint.y or 0) + (dy or 0)

    posX:SetText(tostring(cfg.panelPoint.x))
    posX:SetCursorPosition(0)

    posY:SetText(tostring(cfg.panelPoint.y))
    posY:SetCursorPosition(0)

    ApplyPanelPosition()
end

xMinus:SetScript("OnClick", function()
    NudgePanel(-1, 0)
end)

xPlus:SetScript("OnClick", function()
    NudgePanel(1, 0)
end)

yMinus:SetScript("OnClick", function()
    NudgePanel(0, -1)
end)

yPlus:SetScript("OnClick", function()
    NudgePanel(0, 1)
end)

posX:SetScript("OnEnterPressed", function(self)
    self:ClearFocus()
    ApplyPanelPosition()
end)
posY:SetScript("OnEnterPressed", function(self)
    self:ClearFocus()
    ApplyPanelPosition()
end)
posX:SetScript("OnEditFocusLost", ApplyPanelPosition)
posY:SetScript("OnEditFocusLost", ApplyPanelPosition)

local lock = CreateFrame("CheckButton", nil, f, "UICheckButtonTemplate")
lock:SetPoint("TOPLEFT", enable, "BOTTOMLEFT", 0, -8)
lock.text:SetText(L["InfoPanel_Lock"])

lock:SetScript("OnClick", function(self)
    if syncingUI then return end
    local cfg = EnsureIPConfig()
    if not cfg then return end
    cfg.locked = self:GetChecked() and true or false
    ApplyAll()
end)

local lockHint = f:CreateFontString(nil, "OVERLAY", "GameFontDisableSmall")
lockHint:SetPoint("TOPLEFT", lock, "BOTTOMLEFT", 28, -4)
lockHint:SetText(L["InfoPanel_LockHint"])

local sizeTitle = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
sizeTitle:SetPoint("TOPLEFT", lockHint, "BOTTOMLEFT", -28, -10)
sizeTitle:SetText(L["InfoPanel_Size"])

local function CreateNumberBox(parent, w, h)
    local eb = CreateFrame("EditBox", nil, parent, "InputBoxTemplate")
    eb:SetSize(w, h)
    eb:SetAutoFocus(false)
    eb:SetNumeric(true)
    eb:SetMaxLetters(5)
    eb:SetJustifyH("CENTER")
    eb:SetScript("OnEscapePressed", function(self) self:ClearFocus() end)
    return eb
end

local wLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
wLabel:SetPoint("TOPLEFT", sizeTitle, "BOTTOMLEFT", 5, -8)
wLabel:SetText(L["Width"])

local wSlider = CreateFrame("Slider", "AhUI_InfoPanelWidthSlider", f, "OptionsSliderTemplate")
wSlider:SetPoint("LEFT", wLabel, "RIGHT", 10, 0)
wSlider:SetWidth(280)
wSlider:SetMinMaxValues(50, 3500)
wSlider:SetValueStep(1)
wSlider:SetObeyStepOnDrag(true)
_G[wSlider:GetName().."Low"]:SetText("50")
_G[wSlider:GetName().."High"]:SetText("3500")
_G[wSlider:GetName().."Text"]:SetText("")

local wBox = CreateNumberBox(f, 70, 20)
wBox:SetPoint("LEFT", wSlider, "RIGHT", 10, 0)

local hLabel = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
hLabel:SetPoint("TOPLEFT", wLabel, "BOTTOMLEFT", 0, -18)
hLabel:SetText(L["Height"])

local hSlider = CreateFrame("Slider", "AhUI_InfoPanelHeightSlider", f, "OptionsSliderTemplate")
hSlider:SetPoint("TOPLEFT", wSlider, "BOTTOMLEFT", 0, -18)
hSlider:SetWidth(280)
hSlider:SetMinMaxValues(18, 60)
hSlider:SetValueStep(1)
hSlider:SetObeyStepOnDrag(true)
_G[hSlider:GetName().."Low"]:SetText("18")
_G[hSlider:GetName().."High"]:SetText("60")
_G[hSlider:GetName().."Text"]:SetText("")

local hBox = CreateNumberBox(f, 70, 20)
hBox:SetPoint("LEFT", hSlider, "RIGHT", 10, 0)

wBox:SetScript("OnEnterPressed", function(self)
    if syncingUI then return end
    local v = tonumber(self:GetText())
    if not v then
        RefreshUI()
        self:ClearFocus()
        return
    end

    v = math.floor(v)
    if v < 200 then v = 200 end
    if v > 3440 then v = 3440 end

    local cfg = EnsureIPConfig()
    cfg.appearance.width = v
    ApplyAll()
    RefreshUI()
    self:ClearFocus()
end)

hBox:SetScript("OnEnterPressed", function(self)
    if syncingUI then return end
    local v = tonumber(self:GetText())
    if not v then
        RefreshUI()
        self:ClearFocus()
        return
    end

    v = math.floor(v)
    if v < 18 then v = 18 end
    if v > 60 then v = 60 end

    local cfg = EnsureIPConfig()
    cfg.appearance.height = v
    ApplyAll()
    RefreshUI()
    self:ClearFocus()
end)

local function SyncSizeUI()
    local cfg = EnsureIPConfig()
    if not cfg then return end
    local a = cfg.appearance

    local w = tonumber(a.width) or 800
    local h = tonumber(a.height) or 24

    wSlider:SetValue(w)
    hSlider:SetValue(h)
wBox:SetText(tostring(w))
wBox:SetCursorPosition(0)

hBox:SetText(tostring(h))
hBox:SetCursorPosition(0)

end

wSlider:SetScript("OnValueChanged", function(_, value)
    if syncingUI then return end
    local cfg = EnsureIPConfig()
    if not cfg then return end
    cfg.appearance.width = math.floor(tonumber(value) or 800)
    wBox:SetNumber(cfg.appearance.width)
    ApplyAll()
end)

hSlider:SetScript("OnValueChanged", function(_, value)
    if syncingUI then return end
    local cfg = EnsureIPConfig()
    if not cfg then return end
    cfg.appearance.height = math.floor(tonumber(value) or 24)
    hBox:SetNumber(cfg.appearance.height)
    ApplyAll()
end)

local alphaTitle = f:CreateFontString(nil, "OVERLAY", "GameFontNormal")
alphaTitle:SetPoint("TOPLEFT", hLabel, "BOTTOMLEFT", 0, -18)
alphaTitle:SetText(L["InfoPanel_Alpha"])

local alphaSlider = CreateFrame("Slider", "AhUI_InfoPanelAlphaSlider", f, "OptionsSliderTemplate")
alphaSlider:SetPoint("TOPLEFT", hSlider, "BOTTOMLEFT", 0, -28)
alphaSlider:SetWidth(280)
alphaSlider:SetMinMaxValues(0, 100)
alphaSlider:SetValueStep(1)
alphaSlider:SetObeyStepOnDrag(true)
_G[alphaSlider:GetName().."Low"]:SetText("0%")
_G[alphaSlider:GetName().."High"]:SetText("100%")
_G[alphaSlider:GetName().."Text"]:SetText("")

local alphaBox = CreateNumberBox(f, 70, 20)
alphaBox:SetPoint("LEFT", alphaSlider, "RIGHT", 10, 0)

local function SyncAlphaUI()
    local cfg = EnsureIPConfig()
    if not cfg then return end
    local a = cfg.appearance

    local alpha = tonumber(a.bgAlpha) or 0.7
    alpha = math.max(0, math.min(1, alpha))           
    local alphaPercent = math.floor(alpha * 100 + 0.5) 

    alphaSlider:SetValue(alphaPercent)
    alphaBox:SetText(tostring(alphaPercent))
    alphaBox:SetCursorPosition(0)
end

local function ApplyAlpha(value)
    local cfg = EnsureIPConfig()
    if not cfg then return end

    local alpha = tonumber(value)
    if not alpha then return end

    alpha = math.max(0, math.min(100, alpha)) / 100
    cfg.appearance.bgAlpha = alpha

    ApplyAll()
end

alphaSlider:SetScript("OnValueChanged", function(_, value, userInput)
    if syncingUI or not userInput then return end
    value = math.floor(value + 0.5)
    alphaBox:SetNumber(value)
    ApplyAlpha(value)
end)

alphaBox:SetScript("OnEnterPressed", function(self)
    if syncingUI then return end
    local v = tonumber(self:GetText())
    if not v then
        RefreshUI()
        self:ClearFocus()
        return
    end

    v = math.floor(v + 0.5)
    v = math.max(0, math.min(100, v))

    self:SetText(tostring(v))
    self:ClearFocus()

    ApplyAlpha(v)
    RefreshUI()
end)

alphaBox:SetScript("OnEscapePressed", function(self)
    self:ClearFocus()
    RefreshUI()
end)

local elTitle = f:CreateFontString(nil, "OVERLAY", "GameFontHighlight")
elTitle:SetPoint("TOPLEFT", hLabel, "BOTTOMLEFT", 0, -80)
elTitle:SetText(L["InfoPanel_Elements"])

local listW, listH = 200, 200
local rowH = 22

local function KillScrollFrameTextures(sf)
    for _, region in ipairs({ sf:GetRegions() }) do
        if region and region.GetObjectType and region:GetObjectType() == "Texture" then
            region:SetTexture(nil)
            region:Hide()
        end
    end
end

local function CreateList(parent, anchor, labelText)
    local label = parent:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    label:SetPoint("TOPLEFT", anchor, "BOTTOMLEFT", 0, -8)
    label:SetText(labelText)

    local frame = CreateFrame("Frame", nil, parent, "BackdropTemplate")
    frame:SetPoint("TOPLEFT", label, "BOTTOMLEFT", 0, -4)
    frame:SetSize(listW, listH)
    frame:SetBackdrop({
        bgFile   = "Interface\\Buttons\\WHITE8x8",
        edgeFile = "Interface\\Buttons\\WHITE8x8",
        edgeSize = 2,
    })
    frame:SetBackdropColor(0, 0, 0, 0.6)
    frame:SetBackdropBorderColor(1, 1, 1, 1)

    local scroll = CreateFrame("ScrollFrame", nil, frame)
    scroll:SetPoint("TOPLEFT", 4, -4)
    scroll:SetPoint("BOTTOMRIGHT", -4, 4)
    scroll:EnableMouseWheel(true)
    KillScrollFrameTextures(scroll)

    local content = CreateFrame("Frame", nil, scroll)
    content:SetSize(1, 1)
    scroll:SetScrollChild(content)

    scroll:SetScript("OnMouseWheel", function(self, delta)
        local cur = self:GetVerticalScroll()
        self:SetVerticalScroll(math.max(0, cur - delta * rowH))
    end)

    return label, frame, scroll, content
end

local function MakeDoubleClick(frame, singleClick, doubleClick)
    local lastClick = 0
    frame:SetScript("OnMouseDown", function(_, button)
        if button ~= "LeftButton" then return end
        local now = GetTime()
        if now - lastClick < 0.35 then
            lastClick = 0
            if doubleClick then doubleClick() end
        else
            lastClick = now
            if singleClick then singleClick() end
        end
    end)
end

local bankLabel, bankFrame, bankScroll, bankContent =
    CreateList(f, elTitle, L["InfoPanel_Available"])

local panelLabel, panelFrame, panelScroll, panelContent =
    CreateList(f, bankLabel, L["InfoPanel_OnPanel"])

panelLabel:ClearAllPoints()
panelLabel:SetPoint("TOPLEFT", bankLabel, "TOPRIGHT", 140, 0)
panelFrame:ClearAllPoints()
panelFrame:SetPoint("TOPLEFT", panelLabel, "BOTTOMLEFT", 0, -4)

local btnAdd = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
btnAdd:SetSize(28, 22)
btnAdd:SetPoint("LEFT", bankFrame, "RIGHT", 8, 20)
btnAdd:SetText(L["+"])

local btnRemove = CreateFrame("Button", nil, f, "UIPanelButtonTemplate")
btnRemove:SetSize(28, 22)
btnRemove:SetPoint("TOP", btnAdd, "BOTTOM", 0, -6)
btnRemove:SetText(L["-"])

local function CreateRow(parent, y, text)
    local r = CreateFrame("Frame", nil, parent)
    r:SetSize(listW - 16, rowH)
    r:SetPoint("TOPLEFT", 8, y)

    r.selected = r:CreateTexture(nil, "BACKGROUND")
    r.selected:SetAllPoints()
    r.selected:SetTexture("Interface\\Buttons\\WHITE8x8")
    r.selected:SetColorTexture(1, 1, 1, 0)
    r.selected:Hide()

    r.hover = r:CreateTexture(nil, "BACKGROUND")
    r.hover:SetAllPoints()
    r.hover:SetTexture("Interface\\Buttons\\WHITE8x8")
    r.hover:SetColorTexture(1, 1, 1, 0)

    r:SetScript("OnEnter", function()
        r.hover:SetColorTexture(1, 1, 1, r.isSelected and 0.25 or 0.12)
    end)
    r:SetScript("OnLeave", function()
        r.hover:SetColorTexture(1, 1, 1, 0)
    end)

    r.text = r:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    r.text:SetPoint("LEFT", 6, 0)
    r.text:SetText(text or "")

    return r
end

local selectedBankType
local selectedPanelUID

local function ClearSelection(content)
    for i = 1, content:GetNumChildren() do
        local r = select(i, content:GetChildren())
        if r and r.selected then
            r.selected:Hide()
            r.isSelected = false
        end
    end
end

local function SelectRow(row, content)
    ClearSelection(content)
    row.isSelected = true
    row.selected:Show()
    row.selected:SetColorTexture(1, 1, 1, 0.18)
end

local function GetCharacterCurrencyID(uid)
    if not AhUI_CharConfig or not AhUI_CharConfig.infopanel_currency then
        return nil
    end

    local name, realm = UnitName("player")
    local charKey = name .. "-" .. (realm or "")

    local db = AhUI_CharConfig.infopanel_currency[charKey]
    return db and db[uid] and (db[uid].currencyID or db[uid].currencyId)
end

local function GetCharacterItemID(uid)
    if not AhUI_CharConfig or not AhUI_CharConfig.infopanel_itemslot then return nil end
    local name, realm = UnitName("player")
    local charKey = name .. "-" .. (realm or "")

    local db = AhUI_CharConfig.infopanel_itemslot[charKey]
    return db and db[uid] and db[uid].itemID
end

local function ClearContent(content)
    for i = 1, content:GetNumChildren() do
        select(i, content:GetChildren()):Hide()
    end
end

local function GetElementDisplayName(e, def)
    local name = def and def.name or e.type

    local elementsDB = IP().config and IP().config.elements
    local db = elementsDB and e.uid and elementsDB[e.uid]
    if not db then
        return name
    end

if e.type == "itemslot" then
    local itemID = GetCharacterItemID(e.uid)
    if itemID then
        local _, _, _, _, _, _, _, _, _, icon = C_Item.GetItemInfo(itemID)
        if icon then
            name = name .. " |T" .. icon .. ":14|t"
        end
    end
end

if e.type == "currency" then
    local cid = GetCharacterCurrencyID(e.uid)
    if cid then
        local info = C_CurrencyInfo.GetCurrencyInfo(cid)
        if info and info.iconFileID then
            name = name .. " |T" .. info.iconFileID .. ":14|t"
        end
    end
end

    return name
end


local function RebuildLists()
    ClearContent(bankContent)
    ClearContent(panelContent)

    selectedBankType = nil
    selectedPanelUID = nil

    local typesInfo = IP():GetAvailableElementTypes() or {}

    local onPanel = {}
    for _, e in ipairs(IP().config.layout or {}) do
        local info = typesInfo[e.type]
        if info and not info.multi then
            onPanel[e.type] = true
        end
    end
PT.Settings = PT.Settings or {}
PT.Settings.InfoPanel = PT.Settings.InfoPanel or {}
PT.Settings.InfoPanel.RebuildLists = RebuildLists

    local list = {}
    for _, def in pairs(typesInfo) do
        table.insert(list, def)
    end

    table.sort(list, function(a, b)
        return (a.order or 100) < (b.order or 100)
    end)

    local y = -2
    for _, def in ipairs(list) do

        if not def.multi and onPanel[def.type] then
        else
            local r = CreateRow(bankContent, y, def.name)

            MakeDoubleClick(
                r,
                function()
                    selectedBankType = def.type
                    selectedPanelUID = nil
                    SelectRow(r, bankContent)
                end,
                function()
                    IP():AddElementToPanel(def.type)
                    RebuildLists()
                    ApplyAll()
                end
            )

            y = y - rowH
        end
    end

    bankContent:SetHeight(-y + 4)

    y = -2
    for _, e in ipairs(IP().config.layout or {}) do
        local def = typesInfo[e.type]
		local name = GetElementDisplayName(e, def)

        local r = CreateRow(panelContent, y, name)

        MakeDoubleClick(
            r,
            function()
                selectedPanelUID = e.uid
                selectedBankType = nil
                SelectRow(r, panelContent)
            end,
            function()
                IP():RemoveElementFromPanel(e.uid)
                RebuildLists()
                ApplyAll()
            end
        )

        y = y - rowH
    end

    panelContent:SetHeight(-y + 4)
end

btnAdd:SetScript("OnClick", function()
    if selectedBankType then
        IP():AddElementToPanel(selectedBankType)
        RebuildLists()
        ApplyAll()
    end
end)

btnRemove:SetScript("OnClick", function()
    if selectedPanelUID then
        IP():RemoveElementFromPanel(selectedPanelUID)
        RebuildLists()
        ApplyAll()
    end
end)

function RefreshUI()
    local ip = IP()
    if not ip then return end

    ip:InitConfig()
    local cfg = ip.config
    if not cfg then return end

    syncingUI = true

    enable:SetChecked(cfg.enabled ~= false)
    lock:SetChecked(cfg.locked == true)

    if IP().SyncPositionToUI then
        IP():SyncPositionToUI()
    end

    SyncSizeUI()
	SyncAlphaUI()
    RebuildLists()

    syncingUI = false
end

local function TryRegister()
    if not (PT.Settings and PT.Settings.category) then return end

    local sub = Settings.RegisterCanvasLayoutSubcategory(
        PT.Settings.category,
        f,
        L["Info Panel"]
    )

    if sub and sub.SetOnRefresh then
        sub:SetOnRefresh(RefreshUI)
    else
        sub.OnRefresh = RefreshUI
    end

    RefreshUI()
end

C_Timer.After(0, TryRegister)
