--[[
    Commander 3.0 - Confirmation Prompt System

    Provides Y/N confirmation prompts for destructive actions.
    Uses middleware injection to capture input.

    Single item: [Y/N] prompt
    Multiple items: [A/Y/N] prompt with arrow key navigation
      - Arrow Up/Down: Navigate selection in item list (> indicator)
      - Y: Delete selected item, move to next
      - N: Skip selected item, move to next
      - A: Delete ALL remaining items from selected onwards
      - ESC: Cancel and skip all remaining

    Usage:
        return C3.Prompt.Request({
            message = "Delete this file?",
            onConfirm = function() ... end,
            onCancel = function() ... end,
        })
]]

local ADDON_NAME, C3 = ...

local Prompt = {}
C3.Prompt = Prompt

-- Active prompt state
Prompt._active = nil
Prompt._terminal = nil
Prompt._isSecure = false
Prompt._message = nil     -- Current prompt message
Prompt._animFrame = nil   -- Animation frame for [Y/N] or [A/Y/N] flash
Prompt._animHighlightIndex = 1  -- Which letter is highlighted (1=A/Y, 2=Y/N, 3=N for queue mode)
Prompt._promptLine = nil  -- Reference to output line for updating with result

-- Queue state (for bulk operations)
Prompt._queue = nil
Prompt._queueIndex = 0
Prompt._queueResults = nil
Prompt._queueOptions = nil
Prompt._queueTerminal = nil
Prompt._queueSelectedIndex = 1  -- Currently selected item in list (for > indicator)
Prompt._listLines = nil         -- BufferLine objects for the list display
Prompt._listPageSize = 15       -- Number of items to show at once
Prompt._spinnerIndex = 1

---Strip WoW formatting from a string
---@param text string
---@return string
function Prompt:_stripItemText(text)
    if not text then return "" end
    return text
        :gsub("|c%x%x%x%x%x%x%x%x", "")  -- Color start
        :gsub("|r", "")                   -- Color reset
        :gsub("|T[^|]*|t", "")            -- Texture strings
        :gsub("|H[^|]*|h", "")            -- Hyperlink start
        :gsub("|h", "")                   -- Hyperlink end
        :gsub("||", "|")                  -- Escaped pipes
end

---Get softened hex color for item quality
---@param quality number|nil
---@return string|nil
function Prompt:_getSoftQualityHex(quality)
    if not quality or not ITEM_QUALITY_COLORS then return nil end
    local q = ITEM_QUALITY_COLORS[quality]
    if not q then return nil end

    -- Blend towards a neutral gray to soften the saturation
    local blend = 0.7
    local gray = 0.6
    local r = (q.r * blend) + (gray * (1 - blend))
    local g = (q.g * blend) + (gray * (1 - blend))
    local b = (q.b * blend) + (gray * (1 - blend))

    r = math.max(0, math.min(1, r))
    g = math.max(0, math.min(1, g))
    b = math.max(0, math.min(1, b))

    return string.format("%02X%02X%02X", r * 255, g * 255, b * 255)
end

---Build a clean, consistent display string for queue items
---@param item table
---@param isDone boolean?
---@return string
function Prompt:_buildQueueDisplay(item, isDone)
    local display
    if not isDone and item.link then
        local qualityHex = self:_getSoftQualityHex(item.quality)
        if qualityHex then
            display = item.link:gsub("^|c%x%x%x%x%x%x%x%x", "|cFF" .. qualityHex)
        else
            display = item.link
        end
    else
        local name = self:_stripItemText(item.name or item.link or "Unknown")
        if not isDone then
            local qualityHex = self:_getSoftQualityHex(item.quality)
            if qualityHex then
                name = "|cFF" .. qualityHex .. name .. "|r"
            end
        end
        display = "[" .. name .. "]"
    end

    if item.stackCount and item.stackCount > 1 then
        display = display .. " |cFF777777x" .. item.stackCount .. "|r"
    end

    if item.equipped then
        display = display .. " |cFFAA6666[EQUIPPED]|r"
    end

    return display
end

-------------------------------------------------------------------------------
-- PromptRequest Factory
-------------------------------------------------------------------------------

---Create a prompt request (returned by commands)
---@param options table
---@return table PromptRequest
function Prompt.Request(options)
    return {
        _type = "PromptRequest",
        message = options.message or "Confirm?",
        onConfirm = options.onConfirm,
        onCancel = options.onCancel,
        data = options.data,
    }
end

---Create a queue request for bulk operations (returned by commands)
---@param options table { items, buildMessage, onConfirm, onCancel, onComplete, showList }
---@return table PromptQueueRequest
function Prompt.QueueRequest(options)
    return {
        _type = "PromptQueueRequest",
        items = options.items,
        buildMessage = options.buildMessage,
        onConfirm = options.onConfirm,
        onCancel = options.onCancel,
        onComplete = options.onComplete,
        showList = options.showList,
    }
end

-------------------------------------------------------------------------------
-- Prompt Display
-------------------------------------------------------------------------------

---Show a prompt and wait for user input
---@param request table PromptRequest
---@param terminal table TerminalWindow
---@param secure? boolean If true, callbacks are called synchronously for protected API access
function Prompt:Show(request, terminal, secure)
    if self._active then
        self:Cancel() -- Cancel any existing prompt
    end

    self._active = request
    self._terminal = terminal
    self._isSecure = secure or false

    -- Store the message for animation updates
    self._message = request.message

    -- Display the prompt message
    -- If in queue mode, reuse the existing prompt line to prevent scrolling
    if request.message and request.message ~= "" then
        if self._queue and self._queuePromptLine then
            self._promptLine = self._queuePromptLine
            self._promptLine:SetContent("|cFFEBCB8B" .. request.message .. "|r")
            if terminal.output.renderer then
                terminal.output.renderer:UpdateLine(self._promptLine.id)
            end
        else
            self._promptLine = terminal.output:AddLine(C3.BufferLine.Text("|cFFEBCB8B" .. request.message .. "|r"))
            
            -- Store for queue mode reuse
            if self._queue then
                self._queuePromptLine = self._promptLine
            end
            
            terminal.output:ScrollToBottom()
        end
    end

    -- Set input to read-only mode and show [Y/N] or [A/Y/N] in the prompt area
    local input = terminal.input
    input:SetReadOnly(true)

    -- Replace the "Playername>" prompt with animated [Y/N] or [A/Y/N]
    self._animHighlightIndex = 1
    self:_updateInputPrompt()

    -- Ensure editBox has focus so cursor blinks
    input:Focus()

    -- Start animation
    self:_startAnimation()

    -- Install Y/N middleware (priority position)
    local self_ref = self
    input:AddMiddleware("prompt_yn", function(key, ctrl, shift, alt)
        return self_ref:_handleKey(key)
    end, 1) -- Position 1 for priority
end

---Update the [Y/N] or [A/Y/N] display in the input prompt area
function Prompt:_updateInputPrompt()
    if not self._terminal or not self._terminal.input then return end

    local promptText
    local isQueueMode = self._queue and #self._queue > 1

    if isQueueMode then
        -- Spinner prompt for queue mode
        local frames = C3.Spinner and C3.Spinner.STYLES and C3.Spinner.STYLES.spin or { "-", "\\", "/" }
        local frame = frames[self._spinnerIndex] or "-"
        promptText = "|cFF888888" .. frame .. "|r "
    else
        -- Standard [Y/N] mode
        if self._animHighlightIndex == 1 then
            promptText = "|cFF888888[|cFFFFFFFFY|cFF888888/|cFF666666N|cFF888888]|r "
        else
            promptText = "|cFF888888[|cFF666666Y|cFF888888/|cFFFFFFFFN|cFF888888]|r "
        end
    end

    self._terminal.input:SetPrompt(promptText)
end

-------------------------------------------------------------------------------
-- Animation
-------------------------------------------------------------------------------

---Start the [Y/N] spinner animation
function Prompt:_startAnimation()
    if self._animFrame then return end  -- Already running

    self._animFrame = CreateFrame("Frame")
    self._animFrame.elapsed = 0
    self._animFrame.prompt = self

    self._animFrame:SetScript("OnUpdate", function(frame, elapsed)
        frame.elapsed = frame.elapsed + elapsed
        if frame.elapsed >= 0.5 then  -- Update every 500ms
            frame.elapsed = 0
            frame.prompt:_updateAnimation()
        end
    end)
end

---Stop the spinner animation
function Prompt:_stopAnimation()
    if self._animFrame then
        self._animFrame:SetScript("OnUpdate", nil)
        self._animFrame = nil
    end
end

---Update the [Y/N] or [A/Y/N] animation - cycle which letter is highlighted
function Prompt:_updateAnimation()
    if not self._active or not self._terminal then
        self:_stopAnimation()
        return
    end

    -- Cycle through options
    local isQueueMode = self._queue and #self._queue > 1
    local maxIndex = isQueueMode and 3 or 2

    self._animHighlightIndex = self._animHighlightIndex + 1
    if self._animHighlightIndex > maxIndex then
        self._animHighlightIndex = 1
    end
    if isQueueMode then
        local frames = C3.Spinner and C3.Spinner.STYLES and C3.Spinner.STYLES.spin or { "-", "\\", "/" }
        self._spinnerIndex = self._spinnerIndex + 1
        if self._spinnerIndex > #frames then
            self._spinnerIndex = 1
        end
    end

    -- Update the input prompt area with new state
    self:_updateInputPrompt()
end

-------------------------------------------------------------------------------
-- Key Handling
-------------------------------------------------------------------------------

---Handle key input during prompt
---@param key string
---@return boolean handled
function Prompt:_handleKey(key)
    if not self._active then
        return false
    end

    local keyUpper = key:upper()

    -- Arrow key navigation (only when queue is active with multiple items)
    if self._queue and #self._queue > 1 then
        if key == "UP" then
            self:_navigateQueueSelection(-1)
            return true
        elseif key == "DOWN" then
            self:_navigateQueueSelection(1)
            return true
        end
    end

    if keyUpper == "Y" then
        self:_resolve(true, false)
        return true
    elseif keyUpper == "N" then
        self:_resolve(false, false)
        return true
    elseif keyUpper == "A" and self._queue and #self._queue > 1 then
        -- "A" for delete all (only in queue mode with multiple items)
        self:_resolveAll()
        return true
    elseif key == "ESCAPE" then
        if self._queue and #self._queue > 1 then
            self:_cancelQueueEscape()
        else
            self:_resolve(false, true)  -- wasEscape = true
        end
        return true
    end

    -- Ignore other keys but mark as handled to prevent input
    return true
end

---Navigate queue selection with arrow keys
---@param direction number -1 for up, 1 for down
function Prompt:_navigateQueueSelection(direction)
    if not self._queue or #self._queue <= 1 then return end

    local oldIndex = self._queueSelectedIndex
    local maxIndex = #self._queue
    local newIndex = oldIndex

    -- Find next available (unprocessed) item
    for _ = 1, maxIndex do
        newIndex = newIndex + direction
        if newIndex < 1 then
            newIndex = maxIndex
        elseif newIndex > maxIndex then
            newIndex = 1
        end

        local item = self._queue[newIndex]
        if item and not item._isDone then
            -- Found valid item
            break
        end
    end

    if newIndex ~= oldIndex then
        self._queueSelectedIndex = newIndex
        self:_renderQueueList()
        -- Update the prompt message to show the newly selected item
        self:_updateQueuePromptMessage()
    end
end

---Update the prompt message to show the currently selected item
function Prompt:_updateQueuePromptMessage()
    if self._queue and #self._queue > 1 then return end
    if not self._queue or not self._promptLine then return end

    local item = self._queue[self._queueSelectedIndex]
    if not item then return end

    local message = self._queueOptions.buildMessage(
        item, self._queueSelectedIndex, #self._queue
    )

    -- Update the prompt line text
    self._promptLine:SetContent("|cFFEBCB8B" .. message .. "|r")
    if self._queueTerminal and self._queueTerminal.output.renderer then
        self._queueTerminal.output.renderer:UpdateLine(self._promptLine.id)
    end
end

---Cancel the queue via ESC (skip remaining)
function Prompt:_cancelQueueEscape()
    local results = self._queueResults or { destroyed = {}, skipped = {} }

    if self._queue then
        for _, item in ipairs(self._queue) do
            if not item._isDone then
                table.insert(results.skipped, item)
            end
        end
    end

    self._queueResults = results

    -- Clean up prompt state and restore input
    self:_cleanup(true)
    if self._terminal and self._terminal.input then
        self._terminal.input:UpdatePrompt()
    end

    self:_finishQueue(true)
end

---Resolve all remaining items in the queue (A = delete all)
function Prompt:_resolveAll()
    local request = self._active
    local terminal = self._queueTerminal
    local promptLine = self._promptLine

    -- Clean up prompt state first
    self:_cleanup(false)

    -- Restore normal prompt immediately
    if terminal and terminal.input then
        terminal.input:UpdatePrompt()
    end

    -- Process all remaining items starting from the selected one
    local items = self._queue
    local startIndex = self._queueSelectedIndex
    local results = self._queueResults or { destroyed = {}, skipped = {} }
    local opts = self._queueOptions

    -- Items before selection are skipped
    for i = 1, startIndex - 1 do
        table.insert(results.skipped, items[i])
    end

    -- Show "Destroying all..." message
    if terminal then
        terminal.output:AddLine(C3.BufferLine.Text(
            string.format("|cFFEBCB8BDestroying %d items...|r", #items - startIndex + 1)
        ))
    end

    -- Destroy items with latency spacing
    local index = startIndex - 1
    local function destroyNext()
        index = index + 1
        local item = items[index]

        if not item then
            -- All done - call completion
            local destroyed = results.destroyed
            local skipped = results.skipped
            
            self._queue = nil
            self._queueOptions = nil
            self._queueResults = nil
            self._queueTerminal = nil
            self._queuePromptLine = nil
            self._queueIndex = 0
            self._queueSelectedIndex = 1
            self._listLines = nil

            if opts and opts.onComplete and terminal then
                local result = opts.onComplete(destroyed, skipped)
                if result then
                    terminal:_handleResult(result)
                end
            end
            return
        end

        local result = opts.onConfirm(item)
        table.insert(results.destroyed, item)
        if result and terminal then
            terminal:_handleResult(result)
        end

        -- Mark item done and render update
        item._isDone = true
        item._isDestroyed = true
        self:_renderQueueList()

        -- Continue after latency delay
        C_Timer.After(0.15, destroyNext)
    end

    destroyNext()
end

---Resolve the prompt with user's choice
---@param confirmed boolean
---@param wasEscape boolean? If true, ESC was used to cancel
function Prompt:_resolve(confirmed, wasEscape)
    local request = self._active
    local terminal = self._terminal
    local promptLine = self._promptLine
    -- Check queue mode BEFORE cleanup (cleanup clears _queue)
    local isQueueMode = self._queue and #self._queue > 1

    -- Clean up first (pass wasEscape to suppress OnEscapePressed event)
    self:_cleanup(wasEscape)

    -- Update the original prompt line to append the colored result
    -- Skip queue mode to avoid extra prompt clutter
    if promptLine and terminal and not isQueueMode then
        local selectionText
        if confirmed then
            selectionText = " |cFF888888[|cFF00FF00Y|cFF888888/|cFF666666N|cFF888888]|r"
        else
            selectionText = " |cFF888888[|cFF666666Y|cFF888888/|cFFFF5555N|cFF888888]|r"
        end
        -- Append the selection to the original message
        promptLine:Append(selectionText)
        -- Trigger re-render of this line
        if terminal.output.renderer then
            terminal.output.renderer:UpdateLine(promptLine.id)
        end
    end

    -- Restore normal prompt immediately
    if terminal and terminal.input then
        terminal.input:UpdatePrompt()
    end

    -- Execute the appropriate callback
    local callback = confirmed and request.onConfirm or request.onCancel
    if callback then
        local result = callback()
        if result then
            terminal:_handleResult(result)
        end
    end
end

-------------------------------------------------------------------------------
-- Cleanup
-------------------------------------------------------------------------------

---Cancel the active prompt
function Prompt:Cancel()
    if not self._active then return end

    local request = self._active
    self:_cleanup()

    -- Show cancelled message
    if self._terminal then
        self._terminal.output:AddLine(C3.BufferLine.Text("|cFF888888Cancelled|r"))
    end

    if request.onCancel then
        request.onCancel()
    end
end

---Clean up prompt state
---@param wasEscape boolean? If true, ESC was used to cancel - suppress the OnEscapePressed event
function Prompt:_cleanup(wasEscape)
    -- Stop animation
    self:_stopAnimation()

    if self._terminal and self._terminal.input then
        self._terminal.input:RemoveMiddleware("prompt_yn")
        self._terminal.input:SetReadOnly(false, wasEscape)
    end

    self._active = nil
    self._terminal = nil
    self._isSecure = false
    self._message = nil
    self._promptLine = nil
end

---Check if a prompt is active
---@return boolean
function Prompt:IsActive()
    return self._active ~= nil
end

-------------------------------------------------------------------------------
-- Queue System (for bulk operations like destroy)
-------------------------------------------------------------------------------

---Queue multiple secure prompts for bulk operations
---Shows item list first, then prompts for each item individually
---@param request table PromptQueueRequest { items, buildMessage, onConfirm, onCancel, onComplete, showList }
---@param terminal table TerminalWindow
function Prompt:QueueSecure(request, terminal)
    -- Cancel any existing queue
    if self._queue then
        self:_finishQueue(true)
    end

    self._queue = request.items
    self._queueIndex = 0
    self._queueResults = { destroyed = {}, skipped = {} }
    self._queueOptions = request
    self._queueTerminal = terminal

    -- Show item list first (if more than 1 item and showList not explicitly false)
    if #self._queue > 1 and request.showList ~= false then
        self:_showQueueList()
    end

    -- Start with first item
    self:_showNextInQueue()
end

---Format item for queue list display (stack count, ilvl, equipped)
---@param item table
---@param isDone boolean
---@param isDestroyed boolean
---@return string
function Prompt:_formatQueueItem(item, isDone, isDestroyed)
    return self:_buildQueueDisplay(item, isDone)
end

---Display the list of items (initial setup)
function Prompt:_showQueueList()
    local terminal = self._queueTerminal
    local items = self._queue

    -- Reset selection state
    self._queueSelectedIndex = 1
    self._listLines = {}

    -- Header
    terminal.output:AddLine(C3.BufferLine.Text(
        string.format("|cFFEBCB8BDestroy queue: %d items|r", #items)
    ))
    terminal.output:AddLine(C3.BufferLine.Text(
        "|cFF888888A = all, Y = delete, N = skip, ESC = cancel.|r"
    ))

    -- Create fixed number of lines for the view window
    local visibleCount = math.min(#items, self._listPageSize)
    for i = 1, visibleCount do
        local line = terminal.output:AddLine(C3.BufferLine.Text(""))
        self._listLines[i] = line
    end

    if #items > self._listPageSize then
        terminal.output:AddLine(C3.BufferLine.Text(
            "  |cFF888888... and more|r"
        ))
    end

    terminal.output:AddLine(C3.BufferLine.Text(""))  -- blank line
    
    -- Render initial content
    self:_renderQueueList()
    
    terminal.output:ScrollToBottom()
end

---Render the queue list lines based on current scroll position
function Prompt:_renderQueueList()
    local terminal = self._queueTerminal
    if not terminal or not self._listLines then return end

    local items = self._queue
    local totalItems = #items
    local pageSize = self._listPageSize
    local selected = self._queueSelectedIndex

    -- Calculate scroll window to keep selected item in view
    -- Center selection in window where possible
    local halfPage = math.floor(pageSize / 2)
    local startIdx = selected - halfPage
    
    -- Ensure window fits within bounds
    if startIdx < 1 then 
        startIdx = 1 
    elseif startIdx + pageSize - 1 > totalItems then
        startIdx = math.max(1, totalItems - pageSize + 1)
    end
    
    local endIdx = startIdx + pageSize - 1

    -- Update each visible line
    for i = 1, pageSize do
        local line = self._listLines[i]
        if not line then break end
        
        local itemIdx = startIdx + i - 1
        if itemIdx <= endIdx then
            local item = items[itemIdx]
            local display = self:_formatQueueItem(item, item._isDone, item._isDestroyed)
            local prefix = (itemIdx == selected) and "|cFFFFFFFF>|r " or "  "

            if item._isDone then
                line:SetContent(prefix .. display)
                line.color = item._isDestroyed and "FF0000" or "888888"
            else
                line:SetContent(prefix .. display)
                line.color = nil
            end
            if terminal.output.renderer then
                terminal.output.renderer:UpdateLine(line.id)
            end
        else
            -- Clear unused lines
            line:SetContent("")
            if terminal.output.renderer then
                terminal.output.renderer:UpdateLine(line.id)
            end
        end
    end
end

---Update the > selector when navigating with arrow keys (deprecated, merged into _renderQueueList)
function Prompt:_updateQueueSelection(oldIndex, newIndex)
    -- This function is now just a wrapper for full render since we scroll
    self:_renderQueueList()
end

---Show the next prompt in the queue (uses selected index for navigation)
function Prompt:_showNextInQueue()
    -- Use selected index instead of incrementing queueIndex
    local item = self._queue[self._queueSelectedIndex]

    if not item then
        -- Queue complete
        self:_finishQueue(false)
        return
    end

    local message = ""

    local function getCurrentItem()
        return self._queue and self._queue[self._queueSelectedIndex]
    end

    -- Show secure prompt (onConfirm called synchronously from keypress)
    self:Show({
        message = message,
        onConfirm = function()
            local currentItem = getCurrentItem()
            if not currentItem then return end

            local result = self._queueOptions.onConfirm(currentItem)
            table.insert(self._queueResults.destroyed, currentItem)
            if result then
                self._queueTerminal:_handleResult(result)
            end

            -- Mark item as done
            currentItem._isDone = true
            currentItem._isDestroyed = true

            local currentIndex = self._queueSelectedIndex

            -- Move destroyed item to bottom of the list
            table.remove(self._queue, currentIndex)
            table.insert(self._queue, currentItem)

            -- Render list update immediately to show red status and new position
            self:_renderQueueList()

            -- Check if all items are done
            local allDone = true
            for i = 1, #self._queue do
                if not self._queue[i]._isDone then
                    allDone = false
                    break
                end
            end

            if allDone then
                self:_finishQueue(false)
                return
            end

            -- Find next pending item
            local nextIndex = -1
            
            -- Search forward from current position
            for i = currentIndex, #self._queue do
                if not self._queue[i]._isDone then
                    nextIndex = i
                    break
                end
            end
            
            -- If not found, wrap around to beginning
            if nextIndex == -1 then
                for i = 1, currentIndex - 1 do
                    if not self._queue[i]._isDone then
                        nextIndex = i
                        break
                    end
                end
            end

            -- Move to next unprocessed item automatically
            if nextIndex ~= -1 then
                self._queueSelectedIndex = nextIndex
                self:_renderQueueList()
            end

            -- Continue to next after brief delay (latency for server)
            C_Timer.After(0.15, function()
                self:_showNextInQueue()
            end)
        end,
        onCancel = function()
            -- N = skip current item, move to next
            local currentItem = getCurrentItem()
            if not currentItem then return end

            table.insert(self._queueResults.skipped, currentItem)
            
            -- Mark item as done (skipped)
            currentItem._isDone = true
            currentItem._isDestroyed = false
            
            -- Render list update immediately to show grey status
            self:_renderQueueList()

            -- Check if all items are done and find next
            local allDone = true
            local nextIndex = -1
            local currentIndex = self._queueSelectedIndex

            -- Search forward from current + 1
            for i = currentIndex + 1, #self._queue do
                if not self._queue[i]._isDone then
                    allDone = false
                    if nextIndex == -1 then nextIndex = i end
                    break -- Found immediate next
                end
            end
            
            -- If not found, wrap around to beginning
            if nextIndex == -1 then
                for i = 1, currentIndex do
                    if not self._queue[i]._isDone then
                        allDone = false
                        if nextIndex == -1 then nextIndex = i end
                        break
                    end
                end
            end

            if allDone then
                self:_finishQueue(false)
                return
            end

            -- Move to next unprocessed item
            if nextIndex ~= -1 then
                self._queueSelectedIndex = nextIndex
                self:_renderQueueList()
            end

            -- Continue to next (no delay for skip)
            self:_showNextInQueue()
        end,
    }, self._queueTerminal, true) -- true = secure mode
end

---Finish the queue and call completion callback
---@param cancelled boolean Whether queue was cancelled early
function Prompt:_finishQueue(cancelled)
    local opts = self._queueOptions
    local results = self._queueResults
    local terminal = self._queueTerminal

    -- Clear queue state first
    self._queue = nil
    self._queueOptions = nil
    self._queueResults = nil
    self._queueTerminal = nil
    self._queuePromptLine = nil
    self._queueIndex = 0
    self._queueSelectedIndex = 1
    self._listLines = nil

    if not opts or not terminal then return end

    -- Call completion callback
    if not cancelled and opts.onComplete and results then
        local result = opts.onComplete(results.destroyed, results.skipped)
        if result then
            terminal:_handleResult(result)
        end
    elseif cancelled and opts.onCancel then
        local result = opts.onCancel(results and results.skipped or {})
        if result then
            terminal:_handleResult(result)
        end
    end
end

---Check if a queue is active
---@return boolean
function Prompt:IsQueueActive()
    return self._queue ~= nil
end

return Prompt
