--[[
    Commander 3.0 - Output Display Component

    Renders the VirtualBuffer using VirtualListRenderer (FontString pool).
    This allows true in-place updates - one line change doesn't repaint everything.
]]

local ADDON_NAME, C3 = ...

local DEBUG = false

local function dbg(...)
    if DEBUG then
        print("|cFFFF00FF[OutputDisplay Debug]|r", ...)
    end
end

-- Use shared utilities
local GetThemeColor = function(...) return C3.Colors.GetColor(...) end

-------------------------------------------------------------------------------
-- Output Display Class
-------------------------------------------------------------------------------

local OutputDisplay = C3.class()
C3.UI = C3.UI or {}
C3.UI.OutputDisplay = OutputDisplay

---Create a new output display
---@param parent frame Parent frame
---@param options? table
function OutputDisplay:init(parent, options)
    options = options or {}

    dbg("init() called")

    self.parent = parent
    self.buffer = options.buffer or C3.VirtualBuffer:new()

    dbg("Buffer created/assigned, lineCount=", self.buffer:GetLineCount(), "buffer=", tostring(self.buffer))

    -- Component container (for rich output like icon grids)
    self.componentContainer = CreateFrame("Frame", nil, parent)
    self.componentContainer:SetPoint("TOPLEFT", 4, -8)
    self.componentContainer:SetPoint("TOPRIGHT", -28, -8)
    self.componentContainer:SetHeight(1)
    self.componentContainer:Hide()

    self.componentContainer.bg = self.componentContainer:CreateTexture(nil, "BACKGROUND")
    self.componentContainer.bg:SetAllPoints()
    local contentBg = GetThemeColor("content.bg") or { 0.06, 0.07, 0.09, 0.85 }
    self.componentContainer.bg:SetColorTexture(contentBg[1], contentBg[2], contentBg[3], contentBg[4])

    self.componentContainer.closeBtn = CreateFrame("Button", nil, self.componentContainer)
    self.componentContainer.closeBtn:SetSize(16, 16)
    self.componentContainer.closeBtn:SetPoint("TOPRIGHT", -4, -4)
    self.componentContainer.closeBtn:SetNormalTexture("Interface\\Buttons\\UI-StopButton")
    self.componentContainer.closeBtn:SetHighlightTexture("Interface\\Buttons\\UI-StopButton", "ADD")
    self.componentContainer.closeBtn:SetScript("OnClick", function()
        self:HideComponent()
    end)

    self._activeComponent = nil
    self._activeComponentFrame = nil

    -- Create container frame for the VirtualListRenderer
    -- Leave space at bottom for the inline input line (dynamic based on zoom)
    local Theme = C3.UI.Theme
    local bottomReserve = Theme and Theme:GetEffectiveBottomReserve() or 26
    self.frame = CreateFrame("Frame", nil, parent)
    self.frame:SetPoint("TOPLEFT", self.componentContainer, "BOTTOMLEFT", 0, -4)
    self.frame:SetPoint("BOTTOMRIGHT", 0, bottomReserve)  -- Extend to edge so scrollbar hugs window

    dbg("Container frame created")

    -- Live line tracking
    self._updateTimer = nil
    self._liveLines = {}
    self._visible = true  -- Track visibility for pausing updates

    -- Create the VirtualListRenderer with zoom-aware font size
    local fontSize = Theme and Theme:GetEffectiveFontSize() or 12
    dbg("Creating VirtualListRenderer...")
    self.renderer = C3.UI.VirtualListRenderer:new(self.frame, {
        buffer = self.buffer,
        fontSize = fontSize,
        lineHeight = fontSize + 3,
        scrollbarAnchor = options.scrollbarAnchor,  -- For consistent scrollbar position
    })
    dbg("VirtualListRenderer created")

    -- Save renderer's callback for chaining
    self._rendererOnLineAdded = self.buffer.onLineAdded

    -- Wire up our callback
    self.buffer.onLineAdded = function(line)
        self:_onLineAdded(line)
    end

    dbg("init() complete")
end

-------------------------------------------------------------------------------
-- Line Added Handler
-------------------------------------------------------------------------------

function OutputDisplay:_onLineAdded(line)
    dbg("_onLineAdded called, line.id=", line.id)

    -- Call renderer's callback first
    if self._rendererOnLineAdded then
        self._rendererOnLineAdded(line)
    end

    -- Track live lines
    if line:IsLive() then
        dbg("Tracking live line:", line.id)
        self._liveLines[line.id] = line
        self:_startLiveUpdates()
    end
end

-------------------------------------------------------------------------------
-- Live Updates
-------------------------------------------------------------------------------

function OutputDisplay:_startLiveUpdates()
    if self._updateTimer then return end

    self._updateTimer = C_Timer.NewTicker(0.1, function()
        self:_updateLiveLines()
    end)
end

function OutputDisplay:_stopLiveUpdates()
    if self._updateTimer then
        self._updateTimer:Cancel()
        self._updateTimer = nil
    end
end

function OutputDisplay:_updateLiveLines()
    -- Skip updates if not visible
    if not self._visible then
        return
    end

    local hasLive = false

    for id, line in pairs(self._liveLines) do
        if line:IsLive() then
            hasLive = true
            -- Line updates itself, renderer picks up changes
            self.renderer:UpdateLine(id)
        else
            self._liveLines[id] = nil
        end
    end

    if not hasLive then
        self:_stopLiveUpdates()
    end
end

-------------------------------------------------------------------------------
-- Visibility Control
-------------------------------------------------------------------------------

function OutputDisplay:SetVisible(visible)
    self._visible = visible

    if visible then
        -- Resume: restart watch timers and display update timer
        C3.WatchManager:ResumeAll()
        if next(self._liveLines) then
            self:_startLiveUpdates()
        end
        self.renderer:Render()
    else
        -- Pause: stop all watch timers and display updates
        C3.WatchManager:PauseAll()
        self:_stopLiveUpdates()
    end
end

function OutputDisplay:IsVisible()
    return self._visible
end

---Show or hide renderer content (for TUI takeover mode)
---@param visible boolean
function OutputDisplay:SetRendererVisible(visible)
    if self.renderer then
        self.renderer:SetContentVisible(visible)
    end
end

-------------------------------------------------------------------------------
-- Public API
-------------------------------------------------------------------------------

function OutputDisplay:GetBuffer()
    return self.buffer
end

function OutputDisplay:AddLine(content)
    dbg("AddLine called:", type(content), string.sub(tostring(content), 1, 40))

    -- If already a BufferLine, add directly
    if type(content) == "table" and content.type and content.id then
        dbg("  -> Already a BufferLine, adding directly")
        local line = self.buffer:AddLine(content)
        dbg("  -> Buffer now has", self.buffer:GetLineCount(), "lines")
        return line
    end

    -- Otherwise wrap in Text line
    dbg("  -> Wrapping in BufferLine.Text")
    local line = self.buffer:AddLine(C3.BufferLine.Text(content))
    dbg("  -> Buffer now has", self.buffer:GetLineCount(), "lines")
    return line
end

function OutputDisplay:AddOutput(output)
    return self.buffer:AddLine(C3.BufferLine.Output(output))
end

function OutputDisplay:AddError(message)
    return self.buffer:AddLine(C3.BufferLine.Error(message))
end

function OutputDisplay:AddInput(command, promptText)
    -- Use provided prompt (class-colored) or fallback to simple "> "
    local fullLine = (promptText or "> ") .. command
    return self.buffer:AddLine(C3.BufferLine.Input(fullLine))
end

function OutputDisplay:Clear()
    self.buffer:Clear()
    self:_stopLiveUpdates()
    self._liveLines = {}
    self.renderer:Clear()
    self:HideComponent()
end

function OutputDisplay:Refresh()
    self.renderer:Render()
end

function OutputDisplay:Scroll(delta)
    self.renderer:Scroll(delta)
end

function OutputDisplay:ScrollToBottom()
    self.renderer:ScrollToBottom()
end

function OutputDisplay:ScrollToTop()
    self.renderer:ScrollToTop()
end

function OutputDisplay:PageUp()
    self.renderer:PageUp()
end

function OutputDisplay:PageDown()
    self.renderer:PageDown()
end

-------------------------------------------------------------------------------
-- Component Display (for rich output like icon grids)
-------------------------------------------------------------------------------

function OutputDisplay:ShowComponent(componentType, data)
    self:HideComponent()

    if not C3.UI.RichComponents then
        dbg("RichComponents not available")
        return
    end

    local component = C3.UI.RichComponents:Create(componentType, self.componentContainer, data)
    if not component then
        dbg("Failed to create component:", componentType)
        return
    end

    self._activeComponent = componentType
    self._activeComponentFrame = component

    local height = component:GetHeight() or 100
    self.componentContainer:SetHeight(height + 8)
    self.componentContainer:Show()

    self.frame:SetPoint("TOPLEFT", self.componentContainer, "BOTTOMLEFT", 0, -4)
end

function OutputDisplay:HideComponent()
    if self._activeComponentFrame then
        self._activeComponentFrame:Hide()
        self._activeComponentFrame = nil
    end
    self._activeComponent = nil
    self.componentContainer:SetHeight(1)
    self.componentContainer:Hide()

    self.frame:SetPoint("TOPLEFT", 4, -8)
end

function OutputDisplay:HasComponent()
    return self._activeComponent ~= nil
end

function OutputDisplay:AddComponent(componentType, data)
    self:ShowComponent(componentType, data)

    local line = C3.BufferLine.Text(string.format("[Component: %s]", componentType))
    line:SetMeta("component", componentType)
    line:SetMeta("componentData", data)
    self.buffer:AddLine(line)
end

-------------------------------------------------------------------------------
-- Font Settings
-------------------------------------------------------------------------------

function OutputDisplay:SetFontSize(size)
    self.renderer:SetFontSize(size)
    self.renderer:SetLineHeight(size + 3)
end

function OutputDisplay:GetFontSize()
    return self.renderer.fontSize
end

---Update font size and layout when zoom changes
function OutputDisplay:UpdateFontSize()
    local Theme = C3.UI.Theme
    if not Theme then return end

    local fontSize = Theme:GetEffectiveFontSize()
    local lineHeight = Theme:GetEffectiveLineHeight()
    local bottomReserve = Theme:GetEffectiveBottomReserve()

    -- Update bottom reserve point
    self.frame:ClearAllPoints()
    self.frame:SetPoint("TOPLEFT", self.componentContainer, "BOTTOMLEFT", 0, -4)
    self.frame:SetPoint("BOTTOMRIGHT", 0, bottomReserve)  -- Extend to edge so scrollbar hugs window

    -- Update renderer font and line height
    self.renderer:SetFontSize(fontSize)
    self.renderer:SetLineHeight(lineHeight)
end

-------------------------------------------------------------------------------
-- Context Menu
-------------------------------------------------------------------------------

---Initialize the context menu (called from init or lazily)
function OutputDisplay:_initContextMenu()
    if self.contextMenu then return end

    self.contextMenu = C3.UI.ContextMenu:new(self.frame)

    -- Wire renderer callback
    self.renderer.onContextMenu = function(line, x, y)
        self:_showContextMenu(line, x, y)
    end
end

---Set reference to terminal (needed for input manipulation)
---@param terminal table The TerminalWindow instance
function OutputDisplay:SetTerminal(terminal)
    self.terminal = terminal
    self:_initContextMenu()
end

---Show context menu for a line
---@param line table The BufferLine
---@param x number Screen X coordinate
---@param y number Screen Y coordinate
function OutputDisplay:_showContextMenu(line, x, y)
    if not self.contextMenu then
        self:_initContextMenu()
    end

    local items = {}
    local content = line.content
    local dataType = type(content) == "table" and content._type or nil

    -- Build menu based on type
    self:_addUniversalItems(items, line)

    if dataType then
        table.insert(items, { isSeparator = true })

        if dataType == "Item" then
            self:_addItemActions(items, content)
        elseif dataType == "Spell" then
            self:_addSpellActions(items, content)
        elseif dataType == "Mount" then
            self:_addMountActions(items, content)
        elseif dataType == "Quest" then
            self:_addQuestActions(items, content)
        elseif dataType == "FileEntry" then
            self:_addFileActions(items, content)
        elseif dataType == "GroupMember" or dataType == "GuildMember" then
            self:_addPlayerActions(items, content)
        elseif dataType == "Achievement" then
            self:_addAchievementActions(items, content)
        elseif dataType == "Currency" then
            self:_addCurrencyActions(items, content)
        end
    else
        -- Plain text - add filter option
        self:_addTextFilterAction(items, line)
    end

    self.contextMenu:Show(items, x, y, line)
end

-------------------------------------------------------------------------------
-- Helper Functions
-------------------------------------------------------------------------------

---Quote a string if it contains spaces
---@param str string
---@return string
function OutputDisplay:_quoteIfNeeded(str)
    if not str then return "" end
    if str:find(" ") then
        return '"' .. str .. '"'
    end
    return str
end

---Get the primary identifier from a line (for "Append to Input")
---@param line table BufferLine
---@return string|nil
function OutputDisplay:_getIdentifier(line)
    local content = line.content
    if type(content) ~= "table" then
        return nil
    end

    if content.name then
        return self:_quoteIfNeeded(content.name)
    elseif content.id then
        return tostring(content.id)
    elseif content.path then
        return self:_quoteIfNeeded(content.path)
    end

    return nil
end

---Strip WoW markup from text
---@param text string
---@return string
function OutputDisplay:_cleanText(text)
    if not text then return "" end
    return text
        :gsub("|c%x%x%x%x%x%x%x%x", "")  -- Color codes |cFFRRGGBB
        :gsub("|r", "")                   -- Reset codes
        :gsub("|T[^|]*|t", "")            -- Texture strings |T...|t
        :gsub("|H[^|]*|h", "")            -- Hyperlink start |H...|h
        :gsub("|h", "")                   -- Hyperlink end
        :gsub("||", "|")                  -- Escaped pipes
        :gsub("%[", "")                   -- Square brackets
        :gsub("%]", "")
end

---Get quality name from quality number
---@param quality number
---@return string
function OutputDisplay:_getQualityName(quality)
    local names = {
        [0] = "Poor",
        [1] = "Common",
        [2] = "Uncommon",
        [3] = "Rare",
        [4] = "Epic",
        [5] = "Legendary",
        [6] = "Artifact",
        [7] = "Heirloom",
    }
    return names[quality] or "Unknown"
end

---Open copy popup with text
---@param text string
function OutputDisplay:_openCopyPopup(text)
    if not self._copyPopup then
        self._copyPopup = CreateFrame("Frame", "Commander3CopyPopup", UIParent, "BackdropTemplate")
        self._copyPopup:SetSize(400, 120)
        self._copyPopup:SetPoint("CENTER")
        self._copyPopup:SetFrameStrata("DIALOG")
        self._copyPopup:SetFrameLevel(200)
        self._copyPopup:SetMovable(true)
        self._copyPopup:EnableMouse(true)
        self._copyPopup:RegisterForDrag("LeftButton")
        self._copyPopup:SetScript("OnDragStart", self._copyPopup.StartMoving)
        self._copyPopup:SetScript("OnDragStop", self._copyPopup.StopMovingOrSizing)
        self._copyPopup:SetClampedToScreen(true)

        self._copyPopup:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
            insets = { left = 1, right = 1, top = 1, bottom = 1 },
        })
        local popupBg = GetThemeColor("content.bg") or { 0.06, 0.07, 0.09, 0.85 }
        local popupBorder = GetThemeColor("window.border") or { 0.22, 0.25, 0.31, 0.85 }
        self._copyPopup:SetBackdropColor(popupBg[1], popupBg[2], popupBg[3], 0.95)
        self._copyPopup:SetBackdropBorderColor(popupBorder[1], popupBorder[2], popupBorder[3], popupBorder[4])

        -- Title
        local title = self._copyPopup:CreateFontString(nil, "OVERLAY", "GameFontNormalLarge")
        title:SetPoint("TOP", 0, -8)
        title:SetText("Copy Text")
        title:SetTextColor(1, 1, 1)

        -- Close button
        local closeBtn = CreateFrame("Button", nil, self._copyPopup, "UIPanelCloseButton")
        closeBtn:SetPoint("TOPRIGHT", 0, 0)
        closeBtn:SetScript("OnClick", function() self._copyPopup:Hide() end)

        -- Instruction text
        local inst = self._copyPopup:CreateFontString(nil, "OVERLAY", "GameFontNormalSmall")
        inst:SetPoint("TOP", title, "BOTTOM", 0, -4)
        inst:SetText("Press Ctrl+C to copy")
        inst:SetTextColor(0.7, 0.7, 0.7)

        -- EditBox for copying
        local editBox = CreateFrame("EditBox", nil, self._copyPopup, "BackdropTemplate")
        editBox:SetPoint("TOPLEFT", 12, -50)
        editBox:SetPoint("BOTTOMRIGHT", -12, 12)
        editBox:SetMultiLine(true)
        editBox:SetAutoFocus(false)
        editBox:SetFont("Interface\\AddOns\\Commander3\\fonts\\FiraCode-Regular.ttf", 11, "")
        editBox:SetTextColor(1, 1, 1)

        editBox:SetBackdrop({
            bgFile = "Interface\\ChatFrame\\ChatFrameBackground",
            edgeFile = "Interface\\Buttons\\WHITE8x8",
            edgeSize = 1,
        })
        local inputBg = GetThemeColor("input.bg") or { 0.10, 0.11, 0.14, 0.80 }
        local inputBorder = GetThemeColor("input.border") or { 0.22, 0.25, 0.31, 0.8 }
        editBox:SetBackdropColor(inputBg[1], inputBg[2], inputBg[3], inputBg[4])
        editBox:SetBackdropBorderColor(inputBorder[1], inputBorder[2], inputBorder[3], inputBorder[4])

        editBox:SetScript("OnEscapePressed", function()
            self._copyPopup:Hide()
        end)

        self._copyPopup.editBox = editBox
        self._copyPopup:Hide()
    end

    self._copyPopup.editBox:SetText(text)
    self._copyPopup:Show()
    self._copyPopup.editBox:SetFocus()
    self._copyPopup.editBox:HighlightText()
end

---Smart append filter to input (inserts before sort/take/etc)
---@param whereClause string
function OutputDisplay:_appendFilter(whereClause)
    if not self.terminal or not self.terminal.input then return end

    local input = self.terminal.input
    local current = input:GetText()

    -- If input is empty, try to get last command from history
    if current == "" then
        if self.terminal.session and self.terminal.session.GetLastCommand then
            local lastCmd = self.terminal.session:GetLastCommand()
            if lastCmd then
                current = lastCmd
            end
        end
    end

    -- Smart insertion: insert WHERE before SORT/TAKE/SKIP/SELECT if present
    local insertPoint = current:len() + 1
    local postFixOps = { "| sort", "| take", "| skip", "| first", "| last", "| select" }

    for _, op in ipairs(postFixOps) do
        local pos = current:lower():find(op, 1, true)
        if pos and (pos < insertPoint) then
            insertPoint = pos
        end
    end

    local newText
    if insertPoint <= current:len() then
        -- Insert before sort/take/etc
        local before = current:sub(1, insertPoint - 1):gsub("%s+$", "")
        local after = current:sub(insertPoint)
        newText = before .. " | where " .. whereClause .. " " .. after
    else
        -- Append at end
        newText = current .. " | where " .. whereClause
    end

    input:SetText(newText)
    input:Focus()
end

-------------------------------------------------------------------------------
-- Universal Actions (all lines)
-------------------------------------------------------------------------------

function OutputDisplay:_addUniversalItems(items, line)
    local text = line:GetText()

    -- Quick copy options (fast single-line copy without editor)
    table.insert(items, {
        text = "Copy Text",
        func = function()
            self:_openCopyPopup(text)
        end
    })

    table.insert(items, {
        text = "Copy Clean Text",
        func = function()
            self:_openCopyPopup(self:_cleanText(text))
        end
    })

    if self.terminal and self.terminal.input then
        table.insert(items, {
            text = "Append to Input",
            func = function()
                local identifier = self:_getIdentifier(line)
                if identifier then
                    local current = self.terminal.input:GetText()
                    self.terminal.input:SetText(current .. " " .. identifier)
                    self.terminal.input:Focus()
                end
            end
        })
    end
end

-------------------------------------------------------------------------------
-- Type-Specific Actions
-------------------------------------------------------------------------------

function OutputDisplay:_addItemActions(items, item)
    if item.itemLink then
        table.insert(items, {
            text = "Link to Chat",
            func = function()
                ChatEdit_InsertLink(item.itemLink)
            end
        })

        table.insert(items, {
            text = "Dress Up",
            func = function()
                DressUpItemLink(item.itemLink)
            end
        })
    end

    table.insert(items, {
        text = "Copy Item ID",
        func = function()
            self:_openCopyPopup(tostring(item.itemId or item.id or ""))
        end
    })

    if self.terminal and self.terminal.input then
        table.insert(items, {
            text = "Prepare 'use'",
            func = function()
                self.terminal.input:SetText("use " .. self:_quoteIfNeeded(item.name))
                self.terminal.input:Focus()
            end
        })
    end

    -- Filter by... submenu
    table.insert(items, {
        text = "Filter by...",
        subMenu = function()
            return self:_buildItemFilterSubmenu(item)
        end
    })
end

function OutputDisplay:_buildItemFilterSubmenu(item)
    local subItems = {}

    if item.name then
        table.insert(subItems, {
            text = 'Name: "' .. item.name .. '"',
            func = function()
                self:_appendFilter('name ~ "' .. item.name .. '"')
            end
        })
    end

    if item.quality then
        table.insert(subItems, {
            text = "Quality: " .. self:_getQualityName(item.quality),
            func = function()
                self:_appendFilter("quality == " .. item.quality)
            end
        })
    end

    if item.subType then
        table.insert(subItems, {
            text = "Type: " .. item.subType,
            func = function()
                self:_appendFilter('subType == "' .. item.subType .. '"')
            end
        })
    end

    if item.ilvl and item.ilvl > 0 then
        table.insert(subItems, {
            text = "iLvl >= " .. item.ilvl,
            func = function()
                self:_appendFilter("ilvl >= " .. item.ilvl)
            end
        })
    end

    if item.equipLoc and item.equipLoc ~= "" then
        table.insert(subItems, {
            text = "Slot: " .. item.equipLoc,
            func = function()
                self:_appendFilter('equipLoc == "' .. item.equipLoc .. '"')
            end
        })
    end

    return subItems
end

function OutputDisplay:_addSpellActions(items, spell)
    table.insert(items, {
        text = "Link to Chat",
        func = function()
            local link = C_Spell.GetSpellLink(spell.spellID)
            if link then ChatEdit_InsertLink(link) end
        end
    })

    table.insert(items, {
        text = "Copy Spell ID",
        func = function()
            self:_openCopyPopup(tostring(spell.spellID or spell.id or ""))
        end
    })

    if self.terminal and self.terminal.input then
        table.insert(items, {
            text = "Prepare 'cast'",
            func = function()
                self.terminal.input:SetText("cast " .. self:_quoteIfNeeded(spell.name))
                self.terminal.input:Focus()
            end
        })
    end

    -- Filter by... submenu
    table.insert(items, {
        text = "Filter by...",
        subMenu = function()
            return self:_buildSpellFilterSubmenu(spell)
        end
    })
end

function OutputDisplay:_buildSpellFilterSubmenu(spell)
    local subItems = {}

    if spell.name then
        table.insert(subItems, {
            text = 'Name: "' .. spell.name .. '"',
            func = function()
                self:_appendFilter('name ~ "' .. spell.name .. '"')
            end
        })
    end

    if spell.school then
        table.insert(subItems, {
            text = "School: " .. spell.school,
            func = function()
                self:_appendFilter('school == "' .. spell.school .. '"')
            end
        })
    end

    if spell.isPassive ~= nil then
        table.insert(subItems, {
            text = spell.isPassive and "Is Passive" or "Is Active",
            func = function()
                self:_appendFilter("isPassive == " .. tostring(spell.isPassive))
            end
        })
    end

    return subItems
end

function OutputDisplay:_addMountActions(items, mount)
    table.insert(items, {
        text = "Copy Mount ID",
        func = function()
            self:_openCopyPopup(tostring(mount.id or mount.mountID or ""))
        end
    })

    if self.terminal and self.terminal.input then
        table.insert(items, {
            text = "Prepare 'mount'",
            func = function()
                self.terminal.input:SetText("mount " .. self:_quoteIfNeeded(mount.name))
                self.terminal.input:Focus()
            end
        })
    end

    -- Filter by... submenu
    table.insert(items, {
        text = "Filter by...",
        subMenu = function()
            return self:_buildMountFilterSubmenu(mount)
        end
    })
end

function OutputDisplay:_buildMountFilterSubmenu(mount)
    local subItems = {}

    if mount.name then
        table.insert(subItems, {
            text = 'Name: "' .. mount.name .. '"',
            func = function()
                self:_appendFilter('name ~ "' .. mount.name .. '"')
            end
        })
    end

    if mount.isFlying ~= nil then
        table.insert(subItems, {
            text = mount.isFlying and "Is Flying" or "Not Flying",
            func = function()
                self:_appendFilter("isFlying == " .. tostring(mount.isFlying))
            end
        })
    end

    if mount.isGround ~= nil then
        table.insert(subItems, {
            text = mount.isGround and "Is Ground" or "Not Ground",
            func = function()
                self:_appendFilter("isGround == " .. tostring(mount.isGround))
            end
        })
    end

    if mount.mountType then
        table.insert(subItems, {
            text = "Type: " .. mount.mountType,
            func = function()
                self:_appendFilter("mountType == " .. mount.mountType)
            end
        })
    end

    return subItems
end

function OutputDisplay:_addQuestActions(items, quest)
    table.insert(items, {
        text = "Copy Quest ID",
        func = function()
            self:_openCopyPopup(tostring(quest.id or quest.questID or ""))
        end
    })

    if self.terminal and self.terminal.input then
        table.insert(items, {
            text = "Prepare 'abandon'",
            func = function()
                self.terminal.input:SetText("abandon " .. self:_quoteIfNeeded(quest.name or quest.title or ""))
                self.terminal.input:Focus()
            end
        })
    end

    -- Filter by... submenu
    table.insert(items, {
        text = "Filter by...",
        subMenu = function()
            return self:_buildQuestFilterSubmenu(quest)
        end
    })
end

function OutputDisplay:_buildQuestFilterSubmenu(quest)
    local subItems = {}

    local questName = quest.name or quest.title
    if questName then
        table.insert(subItems, {
            text = 'Name: "' .. questName .. '"',
            func = function()
                self:_appendFilter('name ~ "' .. questName .. '"')
            end
        })
    end

    if quest.level then
        table.insert(subItems, {
            text = "Level: " .. quest.level,
            func = function()
                self:_appendFilter("level == " .. quest.level)
            end
        })
    end

    if quest.isComplete ~= nil then
        table.insert(subItems, {
            text = quest.isComplete and "Completed" or "Incomplete",
            func = function()
                self:_appendFilter("isComplete == " .. tostring(quest.isComplete))
            end
        })
    end

    if quest.isDaily then
        table.insert(subItems, {
            text = "Is Daily",
            func = function()
                self:_appendFilter("isDaily == true")
            end
        })
    end

    if quest.isWeekly then
        table.insert(subItems, {
            text = "Is Weekly",
            func = function()
                self:_appendFilter("isWeekly == true")
            end
        })
    end

    return subItems
end

function OutputDisplay:_addPlayerActions(items, player)
    table.insert(items, {
        text = "Whisper",
        func = function()
            ChatFrame_OpenChat("/w " .. player.name .. " ")
        end
    })

    table.insert(items, {
        text = "Invite",
        func = function()
            InviteUnit(player.name)
        end
    })

    if self.terminal and self.terminal.input then
        table.insert(items, {
            text = "Prepare 'target'",
            func = function()
                self.terminal.input:SetText("target " .. player.name)
                self.terminal.input:Focus()
            end
        })
    end

    table.insert(items, {
        text = "Copy Name",
        func = function()
            self:_openCopyPopup(player.name)
        end
    })

    -- Filter by... submenu
    table.insert(items, {
        text = "Filter by...",
        subMenu = function()
            return self:_buildPlayerFilterSubmenu(player)
        end
    })
end

function OutputDisplay:_buildPlayerFilterSubmenu(player)
    local subItems = {}

    if player.name then
        table.insert(subItems, {
            text = 'Name: "' .. player.name .. '"',
            func = function()
                self:_appendFilter('name ~ "' .. player.name .. '"')
            end
        })
    end

    if player.class then
        table.insert(subItems, {
            text = "Class: " .. player.class,
            func = function()
                self:_appendFilter('class == "' .. player.class .. '"')
            end
        })
    end

    if player.role then
        table.insert(subItems, {
            text = "Role: " .. player.role,
            func = function()
                self:_appendFilter('role == "' .. player.role .. '"')
            end
        })
    end

    if player.isOnline ~= nil then
        table.insert(subItems, {
            text = player.isOnline and "Online" or "Offline",
            func = function()
                self:_appendFilter("isOnline == " .. tostring(player.isOnline))
            end
        })
    end

    return subItems
end

function OutputDisplay:_addFileActions(items, file)
    -- Check if file is executable
    local isExecutable = file.path and (file.path:match("%.lua$") or file.path:match("%.cmd$"))

    table.insert(items, {
        text = "Run Script",
        isDisabled = not isExecutable,
        func = function()
            if C3.Execute then
                C3:Execute("source " .. self:_quoteIfNeeded(file.path))
            end
        end
    })

    if self.terminal and self.terminal.input then
        table.insert(items, {
            text = "Prepare 'rm'",
            func = function()
                self.terminal.input:SetText("rm " .. self:_quoteIfNeeded(file.path))
                self.terminal.input:Focus()
            end
        })
    end

    table.insert(items, {
        text = "Copy Path",
        func = function()
            self:_openCopyPopup(file.path or "")
        end
    })

    -- Filter by... submenu
    table.insert(items, {
        text = "Filter by...",
        subMenu = function()
            return self:_buildFileFilterSubmenu(file)
        end
    })
end

function OutputDisplay:_buildFileFilterSubmenu(file)
    local subItems = {}

    if file.name then
        table.insert(subItems, {
            text = 'Name: "' .. file.name .. '"',
            func = function()
                self:_appendFilter('name ~ "' .. file.name .. '"')
            end
        })
    end

    -- Extension filter
    if file.path then
        local ext = file.path:match("%.([^%.]+)$")
        if ext then
            table.insert(subItems, {
                text = "Extension: ." .. ext,
                func = function()
                    self:_appendFilter('name ~ ".' .. ext .. '"')
                end
            })
        end
    end

    return subItems
end

function OutputDisplay:_addAchievementActions(items, achievement)
    table.insert(items, {
        text = "Copy Achievement ID",
        func = function()
            self:_openCopyPopup(tostring(achievement.id or achievement.achievementID or ""))
        end
    })

    -- Filter by... submenu
    table.insert(items, {
        text = "Filter by...",
        subMenu = function()
            local subItems = {}

            if achievement.name then
                table.insert(subItems, {
                    text = 'Name: "' .. achievement.name .. '"',
                    func = function()
                        self:_appendFilter('name ~ "' .. achievement.name .. '"')
                    end
                })
            end

            if achievement.points then
                table.insert(subItems, {
                    text = "Points >= " .. achievement.points,
                    func = function()
                        self:_appendFilter("points >= " .. achievement.points)
                    end
                })
            end

            if achievement.completed ~= nil then
                table.insert(subItems, {
                    text = achievement.completed and "Completed" or "Incomplete",
                    func = function()
                        self:_appendFilter("completed == " .. tostring(achievement.completed))
                    end
                })
            end

            return subItems
        end
    })
end

function OutputDisplay:_addCurrencyActions(items, currency)
    table.insert(items, {
        text = "Copy Currency ID",
        func = function()
            self:_openCopyPopup(tostring(currency.currencyID or currency.id or ""))
        end
    })

    -- Filter by... submenu
    table.insert(items, {
        text = "Filter by...",
        subMenu = function()
            local subItems = {}

            if currency.name then
                table.insert(subItems, {
                    text = 'Name: "' .. currency.name .. '"',
                    func = function()
                        self:_appendFilter('name ~ "' .. currency.name .. '"')
                    end
                })
            end

            if currency.quantity then
                table.insert(subItems, {
                    text = "Quantity >= " .. currency.quantity,
                    func = function()
                        self:_appendFilter("quantity >= " .. currency.quantity)
                    end
                })
            end

            return subItems
        end
    })
end

function OutputDisplay:_addTextFilterAction(items, line)
    local cleanText = self:_cleanText(line:GetText())
    if cleanText and cleanText ~= "" then
        -- Truncate for display
        local displayText = cleanText:sub(1, 20)
        if #cleanText > 20 then
            displayText = displayText .. "..."
        end

        table.insert(items, {
            text = "Filter by Content",
            func = function()
                self:_appendFilter('text ~ "' .. cleanText:sub(1, 30) .. '"')
            end
        })
    end
end

return OutputDisplay
