local _, addon = ...

addon.Browser = addon.Browser or {}
local Browser = addon.Browser

local TABS = {
    { key = "MOUNTS", label = "Mounts" },
    { key = "SPELLS", label = "Spells" },
    { key = "MACROS", label = "Macros" },
    { key = "COMMANDS", label = "Commands" },
}

local SLOT_ORDER = {
    "NONE",
    "SHIFT",
    "CTRL",
    "ALT",
    "SHIFT_CTRL",
    "SHIFT_ALT",
    "CTRL_ALT",
    "SHIFT_CTRL_ALT",
}

local function normalize(str)
    return string.lower(str or "")
end

local function getSlotLabel(slotKey)
    return addon.Bindings.SLOT_LABELS[slotKey] or slotKey
end

local function sameAction(a, b)
    if not a or not b then
        return false
    end
    return a.type == b.type and tostring(a.id) == tostring(b.id)
end

function Browser:Initialize()
    self.activeTab = "MOUNTS"
    self.searchText = ""
    self.showUncollected = false
    self.pendingAssignment = nil
end

function Browser:GetDataForActiveTab()
    if self.activeTab == "MOUNTS" then
        return addon.Actions:GetMountActions(self.showUncollected)
    elseif self.activeTab == "SPELLS" then
        return addon.Actions:GetKnownTravelSpells(false)
    elseif self.activeTab == "MACROS" then
        return addon.Actions:GetMacroActions()
    elseif self.activeTab == "COMMANDS" then
        return addon.Actions:GetCuratedCommands()
    end
    return {}
end

function Browser:GetFilteredData()
    local data = self:GetDataForActiveTab()
    local search = normalize(self.searchText)
    if search == "" then
        return data
    end

    local out = {}
    for _, item in ipairs(data) do
        if string.find(normalize(item.name), search, 1, true) then
            out[#out + 1] = item
        end
    end
    return out
end

function Browser:SelectItem(row)
    self.selected = row
    if self.selectionText then
        if row then
            self.selectionText:SetText("Selected: " .. row.name .. " [" .. row.type .. "]")
        else
            self.selectionText:SetText("Selected: none")
        end
    end
end

function Browser:SetPendingAssignment(actionRef)
    self.pendingAssignment = actionRef
    if self.pendingHint then
        if actionRef then
            self.pendingHint:SetText("Assign mode: click a slot tile to place this action.")
        else
            self.pendingHint:SetText("|cff7f7f7fSelect or drag an action to assign.|r")
        end
    end
    self:UpdateCursorPreview()
    self:UpdateSlotModeHighlight()
end

function Browser:UpdateCursorPreview()
    if not self.cursorPreview then
        return
    end
    local actionRef = self.draggingAction or self.pendingAssignment
    if actionRef and actionRef.icon then
        self.cursorPreview.icon:SetTexture(actionRef.icon)
        self.cursorPreview:Show()
    else
        self.cursorPreview:Hide()
    end
end

function Browser:UpdateSlotModeHighlight()
    if not self.summarySlots then
        return
    end
    local active = (self.draggingAction ~= nil) or (self.pendingAssignment ~= nil)
    for _, slot in ipairs(self.summarySlots) do
        if active then
            slot:SetBackdropColor(0.08, 0.12, 0.18, 0.88)
        else
            slot:SetBackdropColor(0.05, 0.05, 0.05, 0.8)
        end
    end
end

function Browser:AssignSelectedToBindingSlot(slotKey)
    if not self.selected or not slotKey then
        return
    end
    addon:SetBindingSlotAction(slotKey, self.selected)
    self:RefreshBindingSummary()
end

function Browser:ClearBindingSlot(slotKey)
    if not slotKey then
        return
    end
    addon:SetBindingSlotAction(slotKey, nil)
    self:RefreshBindingSummary()
end

function Browser:RefreshBindingSummary()
    if not self.summarySlots then
        return
    end

    for i, slotKey in ipairs(SLOT_ORDER) do
        local slot = self.summarySlots[i]
        if slot then
            local actionRef = addon:GetBindingSlotAction(slotKey)
            if actionRef then
                slot.icon:SetTexture(actionRef.icon or 134400)
                slot.name:SetText(actionRef.name or "(unnamed)")
            else
                slot.icon:SetTexture(134400)
                slot.name:SetText("(empty)")
            end
        end
    end
end

function Browser:RefreshList()
    if not self.listButtons then
        return
    end

    self.currentData = self:GetFilteredData()
    local rowHeight = 28
    local visibleRows = #self.listButtons
    FauxScrollFrame_Update(self.scrollFrame, #self.currentData, visibleRows, rowHeight)
    local offset = FauxScrollFrame_GetOffset(self.scrollFrame)

    for i = 1, visibleRows do
        local btn = self.listButtons[i]
        local row = self.currentData[i + offset]
        if row then
            btn.row = row
            btn.icon:SetTexture(row.icon or 134400)
            btn.text:SetText(row.name .. " |cff808080(" .. row.type .. ")|r")
            if sameAction(row, self.selected) then
                btn:GetNormalTexture():SetVertexColor(0.22, 0.36, 0.6, 0.55)
            else
                btn:GetNormalTexture():SetVertexColor(1, 1, 1, 0.04)
            end
            btn:Show()
        else
            btn.row = nil
            btn:Hide()
        end
    end
end

function Browser:BuildUI(parent)
    self:Initialize()

    local root = CreateFrame("Frame", nil, parent)
    root:SetAllPoints(parent)
    self.root = root
    root:SetScript("OnMouseUp", function()
        self.draggingAction = nil
        self:UpdateCursorPreview()
        self:UpdateSlotModeHighlight()
    end)

    local cursorPreview = CreateFrame("Frame", nil, UIParent, "BackdropTemplate")
    cursorPreview:SetSize(28, 28)
    cursorPreview:SetFrameStrata("FULLSCREEN_DIALOG")
    cursorPreview:SetFrameLevel(200)
    cursorPreview:SetBackdrop({
        bgFile = "Interface/Buttons/WHITE8x8",
        edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
        edgeSize = 8,
        insets = { left = 1, right = 1, top = 1, bottom = 1 },
    })
    cursorPreview:SetBackdropColor(0, 0, 0, 0.8)
    cursorPreview.icon = cursorPreview:CreateTexture(nil, "ARTWORK")
    cursorPreview.icon:SetAllPoints()
    cursorPreview:Hide()
    cursorPreview:SetScript("OnUpdate", function(frame)
        local x, y = GetCursorPosition()
        local scale = UIParent:GetEffectiveScale()
        frame:ClearAllPoints()
        frame:SetPoint("CENTER", UIParent, "BOTTOMLEFT", x / scale + 16, y / scale - 16)
    end)
    self.cursorPreview = cursorPreview

    local searchLabel = root:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    searchLabel:SetPoint("TOPLEFT", 0, -4)
    searchLabel:SetText("Search")

    local search = CreateFrame("EditBox", nil, root, "InputBoxTemplate")
    search:SetSize(280, 26)
    search:SetPoint("TOPLEFT", searchLabel, "BOTTOMLEFT", 0, -6)
    search:SetAutoFocus(false)
    search:SetScript("OnTextChanged", function(edit)
        self.searchText = edit:GetText() or ""
        self:RefreshList()
    end)

    local tabStartX = 0
    for i, tab in ipairs(TABS) do
        local button = CreateFrame("Button", nil, root, "UIPanelButtonTemplate")
        button:SetSize(122, 24)
        local row = math.floor((i - 1) / 2)
        local col = (i - 1) % 2
        button:SetPoint("TOPLEFT", tabStartX + col * 126, -64 - row * 28)
        button:SetText(tab.label)
        button:SetScript("OnClick", function()
            self.activeTab = tab.key
            self:RefreshList()
        end)
    end

    local listFrame = CreateFrame("Frame", nil, root, "BackdropTemplate")
    listFrame:SetPoint("TOPLEFT", 0, -126)
    listFrame:SetPoint("BOTTOMRIGHT", root, "BOTTOMRIGHT", -300, 0)
    listFrame:SetBackdrop({
        bgFile = "Interface/Buttons/WHITE8x8",
        edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
        edgeSize = 10,
        insets = { left = 2, right = 2, top = 2, bottom = 2 },
    })
    listFrame:SetBackdropColor(0.08, 0.08, 0.08, 0.7)

    local scroll = CreateFrame("ScrollFrame", "MountBinderBrowserScrollFrame", listFrame, "FauxScrollFrameTemplate")
    scroll:SetPoint("TOPLEFT", 0, -4)
    scroll:SetPoint("BOTTOMRIGHT", -24, 4)
    scroll:SetScript("OnVerticalScroll", function(frame, offset)
        FauxScrollFrame_OnVerticalScroll(frame, offset, 28, function()
            self:RefreshList()
        end)
    end)
    self.scrollFrame = scroll

    self.listButtons = {}
    for i = 1, 11 do
        local row = CreateFrame("Button", nil, listFrame)
        row:SetPoint("TOPLEFT", 10, -8 - (i - 1) * 28)
        row:SetPoint("TOPRIGHT", -30, -8 - (i - 1) * 28)
        row:SetHeight(26)
        row:SetNormalTexture("Interface/Buttons/WHITE8x8")
        row:GetNormalTexture():SetVertexColor(1, 1, 1, 0.04)
        row:SetHighlightTexture("Interface/Buttons/WHITE8x8")
        row:GetHighlightTexture():SetVertexColor(0.2, 0.55, 0.9, 0.35)

        row.icon = row:CreateTexture(nil, "ARTWORK")
        row.icon:SetSize(18, 18)
        row.icon:SetPoint("LEFT", 4, 0)

        row.text = row:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        row.text:SetPoint("LEFT", row.icon, "RIGHT", 6, 0)
        row.text:SetPoint("RIGHT", -6, 0)
        row.text:SetJustifyH("LEFT")

        row:SetScript("OnClick", function(button)
            self:SelectItem(button.row)
            self:SetPendingAssignment(button.row)
            self:RefreshList()
            self:UpdateSlotModeHighlight()
        end)
        row:RegisterForDrag("LeftButton")
        row:SetScript("OnDragStart", function(button)
            self.draggingAction = button.row
            self:SelectItem(button.row)
            self:SetPendingAssignment(button.row)
            self:RefreshList()
            self:UpdateSlotModeHighlight()
        end)
        row:SetScript("OnDragStop", function()
            self.draggingAction = nil
            self:UpdateCursorPreview()
            self:UpdateSlotModeHighlight()
        end)
        self.listButtons[i] = row
    end

    local rightPanel = CreateFrame("Frame", nil, root, "BackdropTemplate")
    rightPanel:SetPoint("TOPLEFT", listFrame, "TOPRIGHT", 10, 0)
    rightPanel:SetPoint("BOTTOMRIGHT", root, "BOTTOMRIGHT", 0, 0)
    rightPanel:SetBackdrop({
        bgFile = "Interface/Buttons/WHITE8x8",
        edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
        edgeSize = 10,
        insets = { left = 2, right = 2, top = 2, bottom = 2 },
    })
    rightPanel:SetBackdropColor(0.07, 0.07, 0.07, 0.7)

    self.selectionText = rightPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    self.selectionText:SetPoint("TOPLEFT", 8, -10)
    self.selectionText:SetPoint("TOPRIGHT", -8, -10)
    self.selectionText:SetJustifyH("LEFT")
    self.selectionText:SetText("Selected: none")
    self.pendingHint = rightPanel:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
    self.pendingHint:SetPoint("TOPLEFT", self.selectionText, "BOTTOMLEFT", 0, -4)
    self.pendingHint:SetPoint("TOPRIGHT", -8, -4)
    self.pendingHint:SetJustifyH("LEFT")
    self.pendingHint:SetText("|cff7f7f7fSelect or drag an action to assign.|r")

    local slotLabel = rightPanel:CreateFontString(nil, "OVERLAY", "GameFontNormal")
    slotLabel:SetPoint("TOPLEFT", self.pendingHint, "BOTTOMLEFT", 0, -12)
    slotLabel:SetText("Binding Slot")

    local slotDropdown = CreateFrame("Frame", "MountBinderSettingsSlotDropdown", rightPanel, "UIDropDownMenuTemplate")
    slotDropdown:SetPoint("TOPLEFT", slotLabel, "BOTTOMLEFT", -16, -2)
    UIDropDownMenu_SetWidth(slotDropdown, 180)
    UIDropDownMenu_SetText(slotDropdown, "No Mod")
    self.bindingSlotChoice = "NONE"

    UIDropDownMenu_Initialize(slotDropdown, function(_, level)
        local info = UIDropDownMenu_CreateInfo()
        for _, slotKey in ipairs(SLOT_ORDER) do
            local label = getSlotLabel(slotKey)
            info.text = label
            info.func = function()
                self.bindingSlotChoice = slotKey
                UIDropDownMenu_SetText(slotDropdown, label)
                self:RefreshBindingSummary()
            end
            UIDropDownMenu_AddButton(info, level)
        end
    end)

    local assignBtn = CreateFrame("Button", nil, rightPanel, "UIPanelButtonTemplate")
    assignBtn:SetSize(106, 24)
    assignBtn:SetPoint("TOPLEFT", slotDropdown, "BOTTOMLEFT", 20, -4)
    assignBtn:SetText("Assign")
    assignBtn:SetScript("OnClick", function()
        self:AssignSelectedToBindingSlot(self.bindingSlotChoice or "NONE")
    end)

    local clearBtn = CreateFrame("Button", nil, rightPanel, "UIPanelButtonTemplate")
    clearBtn:SetSize(106, 24)
    clearBtn:SetPoint("LEFT", assignBtn, "RIGHT", 8, 0)
    clearBtn:SetText("Clear")
    clearBtn:SetScript("OnClick", function()
        self:ClearBindingSlot(self.bindingSlotChoice or "NONE")
    end)

    local clearAllBtn = CreateFrame("Button", nil, rightPanel, "UIPanelButtonTemplate")
    clearAllBtn:SetSize(220, 24)
    clearAllBtn:SetPoint("TOPLEFT", assignBtn, "BOTTOMLEFT", 0, -10)
    clearAllBtn:SetText("Clear All Bindings")
    clearAllBtn:SetScript("OnClick", function()
        for _, slotKey in ipairs(SLOT_ORDER) do
            addon:SetBindingSlotAction(slotKey, nil)
        end
        self:RefreshBindingSummary()
    end)

    self.summarySlots = {}
    local cols = 4
    local slotW = 54
    local slotH = 58
    local startX = 2
    local startY = -18
    for i, slotKey in ipairs(SLOT_ORDER) do
        local idx = i - 1
        local row = math.floor(idx / cols)
        local col = idx % cols

        local holder = CreateFrame("Frame", nil, rightPanel, "BackdropTemplate")
        holder:SetSize(slotW, slotH)
        holder:SetPoint("TOPLEFT", clearAllBtn, "BOTTOMLEFT", startX + col * (slotW + 2), startY - row * (slotH + 30))
        holder:SetBackdrop({
            bgFile = "Interface/Buttons/WHITE8x8",
            edgeFile = "Interface/Tooltips/UI-Tooltip-Border",
            edgeSize = 8,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })
        holder:SetBackdropColor(0.05, 0.05, 0.05, 0.8)
        holder.slotKey = slotKey
        holder:EnableMouse(true)
        holder:SetScript("OnEnter", function(tile)
            if self.draggingAction or self.pendingAssignment then
                tile:SetBackdropColor(0.18, 0.24, 0.33, 0.95)
            else
                tile:SetBackdropColor(0.05, 0.05, 0.05, 0.8)
            end
        end)
        holder:SetScript("OnLeave", function()
            self:UpdateSlotModeHighlight()
        end)
        holder:SetScript("OnMouseUp", function(tile)
            local assignRef = self.draggingAction or self.pendingAssignment or self.selected
            if assignRef then
                addon:SetBindingSlotAction(tile.slotKey, assignRef)
                self.draggingAction = nil
                self:SetPendingAssignment(nil)
                self:RefreshBindingSummary()
                self:RefreshList()
                self.pendingHint:SetText("|cff7f7f7fAssigned. Select or drag another action.|r")
                self:UpdateSlotModeHighlight()
            end
        end)

        holder.label = rightPanel:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        holder.label:SetPoint("BOTTOMLEFT", holder, "TOPLEFT", 0, 4)
        holder.label:SetPoint("BOTTOMRIGHT", holder, "TOPRIGHT", 0, 4)
        holder.label:SetJustifyH("CENTER")
        holder.label:SetText(getSlotLabel(slotKey))

        holder.icon = holder:CreateTexture(nil, "ARTWORK")
        holder.icon:SetSize(26, 26)
        holder.icon:SetPoint("TOP", 0, -4)

        holder.name = holder:CreateFontString(nil, "OVERLAY", "GameFontHighlightSmall")
        holder.name:SetPoint("TOPLEFT", holder.icon, "BOTTOMLEFT", -12, -2)
        holder.name:SetPoint("TOPRIGHT", holder.icon, "BOTTOMRIGHT", 12, -2)
        holder.name:SetJustifyH("CENTER")
        holder.name:SetMaxLines(2)

        self.summarySlots[i] = holder
    end

    self:RefreshBindingSummary()
    self:RefreshList()
    self:UpdateCursorPreview()
    self:UpdateSlotModeHighlight()
    return root
end
