containerSettings = nil

function init()
    g_ui.importStyle('container')

    -- Initialize container settings
    containerSettings = g_settings.getNode('containers')
    if not containerSettings then
        containerSettings = {}
        -- Set useManualSortMode as default
        containerSettings['useManualSortMode'] = 1
        -- Set default sorting mode to none
        containerSettings['currentSortMode'] = 'none'
        -- Initialize sorting options
        containerSettings['sortContainersFirst'] = 0
        containerSettings['sortNestedContainers'] = 0
        g_settings.setNode('containers', containerSettings)
    end

    -- Ensure all required settings exist
    if containerSettings['sortNestedContainers'] == nil then
        containerSettings['sortNestedContainers'] = 0
    end
    if containerSettings['sortContainersFirst'] == nil then
        containerSettings['sortContainersFirst'] = 0
    end

    connect(Container, {
        onOpen = onContainerOpen,
        onClose = onContainerClose,
        onSizeChange = onContainerChangeSize,
        onUpdateItem = onContainerUpdateItem
    })
    connect(Game, {
        onGameEnd = clean()
    })

    reloadContainers()
end

function terminate()
    disconnect(Container, {
        onOpen = onContainerOpen,
        onClose = onContainerClose,
        onSizeChange = onContainerChangeSize,
        onUpdateItem = onContainerUpdateItem
    })
    disconnect(Game, {
        onGameEnd = clean()
    })
end

function reloadContainers()
    clean()
    for _, container in pairs(g_game.getContainers()) do
        onContainerOpen(container)
    end
end

function clean()
    for containerid, container in pairs(g_game.getContainers()) do
        destroy(container)
    end
end

function destroy(container)
    if container.window then
        container.window:destroy()
        container.window = nil
        container.itemsPanel = nil
    end
end

function showContainersContextMenu(widget, mousePos, mouseButton)
    local menu = g_ui.createWidget('ContainersSubMenu')
    if not menu then
        return false
    end
    menu:setGameMenu(true)
    for _, choice in ipairs(menu:getChildren()) do
        local choiceId = choice:getId()
        if choiceId and choiceId ~= 'HorizontalSeparator' then
            local widgetClass = choice:getClassName()
            local isSortingAction = choiceId:find('sortAsc') or choiceId:find('sortDesc')
            local isActionButton = isSortingAction or choiceId == 'moveToObtainContainers'
            if isActionButton then
                choice.onClick = function()
                    onContainersMenuAction(choiceId)
                    menu:destroy()
                end
                choice.onMouseRelease = function(widget, mousePos, mouseButton)
                    if mouseButton == MouseLeftButton then
                        onContainersMenuAction(choiceId)
                        menu:destroy()
                        return true
                    end
                    return false
                end
                if isSortingAction then
                    local currentSortMode = containerSettings and containerSettings['currentSortMode'] or 'none'
                    local isActive = (currentSortMode == choiceId)
                    local isManualSortEnabled = containerSettings and containerSettings['useManualSortMode'] == 1
                    if isManualSortEnabled then
                        choice:setEnabled(false)
                        choice:setColor('#808080')
                    else
                        choice:setEnabled(true)
                        if isActive then
                            choice:setColor('#ffff00')
                        else
                            choice:setColor('#ffffff')
                        end
                    end
                else
                    choice:setEnabled(true)
                    choice:setColor('#ffffff')
                end
            else
                local currentState = getContainerOptionState(choiceId)
                choice:setChecked(currentState)
                local isManualSortEnabled = containerSettings and containerSettings['useManualSortMode'] == 1
                if isManualSortEnabled and (choiceId == 'sortContainersFirst' or choiceId == 'sortNestedContainers') then
                    choice:setEnabled(false)
                    choice:setColor('#808080')
                else
                    choice:setEnabled(true)
                    choice:setColor('#ffffff')
                end
                choice.onCheckChange = function()
                    onContainersMenuAction(choiceId)
                    menu:destroy()
                end
            end
        end
    end
    local buttonPos = widget:getPosition()
    local buttonSize = widget:getSize()
    local menuWidth = menu:getWidth()
    local buttonCenterX = buttonPos.x + buttonSize.width / 2
    local buttonCenterY = buttonPos.y + buttonSize.height / 2
    local menuX = buttonCenterX - menuWidth
    local menuY = buttonCenterY
    menu:display({x = menuX, y = menuY})
    return true
end

function getContainerOptionState(optionId)
    -- Return the current state of container options
    -- These are stored in settings similar to skills module
    if not containerSettings then
        return false
    end
    
    if optionId == 'sortContainersFirst' then
        return containerSettings['sortContainersFirst'] == 1
    elseif optionId == 'sortNestedContainers' then
        return containerSettings['sortNestedContainers'] == 1
    elseif optionId == 'useManualSortMode' then
        return containerSettings['useManualSortMode'] == 1
    elseif optionId == 'moveNestedContainers' then
        return containerSettings['moveNestedContainers'] == 1
    end
    return false
end

function sortContainerItems(container, sortMode)
    if not container or not container.itemsPanel then
        return
    end
    
    -- Don't sort if manual sort mode is enabled
    local isManualSortEnabled = containerSettings and containerSettings['useManualSortMode'] == 1
    if isManualSortEnabled then
        return
    end
    
    -- Check if Sort Nested Containers is enabled when manual sort mode is disabled
    local sortNestedContainers = containerSettings and containerSettings['sortNestedContainers'] == 1
    if sortNestedContainers then
    end
    
    -- Get all items with their slot information (only non-nil items)
    local items = {}
    local totalCapacity = container:getCapacity()
    
    for slot = 0, totalCapacity - 1 do
        local item = container:getItem(slot)
        if item and item:getId() > 0 then -- Check for valid item
            table.insert(items, {
                slot = slot,
                item = item,
                widget = container.itemsPanel:getChildById('item' .. slot)
            })
        end
    end
    
    -- Only sort if we have items
    if #items == 0 then
        return
    end
    
    -- Check if Sort Containers First and Sort Nested Containers are enabled
    local sortContainersFirst = containerSettings and containerSettings['sortContainersFirst'] == 1
    local sortNestedContainers = containerSettings and containerSettings['sortNestedContainers'] == 1
    
    -- Helper function to check if an item is a container
    local function isContainer(item)
        local success, result = pcall(function()
            if item.isContainer and type(item.isContainer) == "function" then
                return item:isContainer()
            end
            return false
        end)
        return success and result
    end
    
    -- Helper function to check if a container has items inside (is nested)
    local function isNestedContainer(item)
        if not isContainer(item) then
            return false
        end
        
        local success, result = pcall(function()
            -- Try to get the container's item count
            if item.getItemsCount and type(item.getItemsCount) == "function" then
                local itemCount = item:getItemsCount()
                return itemCount and itemCount > 0
            end
            
            -- Alternative: Check if container has capacity and items
            if item.getCapacity and type(item.getCapacity) == "function" then
                local capacity = item:getCapacity()
                if capacity and capacity > 0 then
                    -- Check if any slot has an item
                    for slot = 0, capacity - 1 do
                        if item.getItem and type(item.getItem) == "function" then
                            local slotItem = item:getItem(slot)
                            if slotItem and slotItem:getId() > 0 then
                                return true
                            end
                        end
                    end
                end
            end
            
            return false
        end)
        
        if not success then
            return false
        end
        
        return result
    end
    
    -- Helper function for container-first sorting with nested container support
    local function sortWithContainersFirst(items, compareFn)
        local sortContainersFirst = containerSettings and containerSettings['sortContainersFirst'] == 1
        local sortNestedContainers = containerSettings and containerSettings['sortNestedContainers'] == 1
        
        -- Sort Nested Containers feature:
        -- When enabled, containers that have items inside them are prioritized at the top,
        -- followed by empty containers (if Sort Containers First is also enabled),
        -- and finally non-container items.
        -- 
        -- Priority order when both options are enabled:
        -- 1. Nested containers (containers with items inside) - HIGHEST PRIORITY
        -- 2. Empty containers (only if Sort Containers First is enabled)
        -- 3. Non-container items - LOWEST PRIORITY
        -- 
        -- This feature can work together with Sort Containers First but not with Manual Sort Mode.
        
        -- If neither option is enabled, just sort normally
        if not sortContainersFirst and not sortNestedContainers then
            table.sort(items, compareFn)
            return
        end
        
        -- Separate items into categories
        local nestedContainers = {}      -- Containers with items inside
        local emptyContainers = {}       -- Empty containers
        local nonContainers = {}         -- Non-container items
        
        for _, itemData in ipairs(items) do
            if isContainer(itemData.item) then
                if sortNestedContainers and isNestedContainer(itemData.item) then
                    table.insert(nestedContainers, itemData)
                else
                    table.insert(emptyContainers, itemData)
                end
            else
                table.insert(nonContainers, itemData)
            end
        end
        
        -- Sort each group separately
        table.sort(nestedContainers, compareFn)
        table.sort(emptyContainers, compareFn)
        table.sort(nonContainers, compareFn)
        
        -- Merge groups based on enabled options with proper priority order
        local sortedItems = {}
        
        -- Priority 1: Nested containers (if Sort Nested Containers is enabled)
        if sortNestedContainers then
            for _, itemData in ipairs(nestedContainers) do
                table.insert(sortedItems, itemData)
            end
        end
        
        -- Priority 2: Empty containers (if Sort Containers First is enabled)
        -- Note: This comes after nested containers even if both options are enabled
        if sortContainersFirst then
            for _, itemData in ipairs(emptyContainers) do
                table.insert(sortedItems, itemData)
            end
            
            -- Add nested containers here only if sortNestedContainers is not enabled
            if not sortNestedContainers then
                for _, itemData in ipairs(nestedContainers) do
                    table.insert(sortedItems, itemData)
                end
            end
        else
            -- If sortContainersFirst is disabled but sortNestedContainers is disabled too,
            -- add all containers together after nested containers
            if not sortNestedContainers then
                for _, itemData in ipairs(nestedContainers) do
                    table.insert(sortedItems, itemData)
                end
            end
            
            -- Add empty containers without priority
            for _, itemData in ipairs(emptyContainers) do
                table.insert(sortedItems, itemData)
            end
        end
        
        -- Priority 3 (Last): Non-container items
        for _, itemData in ipairs(nonContainers) do
            table.insert(sortedItems, itemData)
        end
        
        -- Replace original items array
        for i = 1, #items do
            items[i] = sortedItems[i]
        end
    end
    
    -- Sort the items based on the sort mode
    if sortMode == 'sortAscByName' then
        sortWithContainersFirst(items, function(a, b) 
            if not a or not a.item or not b or not b.item then 
                return false 
            end
            
            local nameA = ""
            local nameB = ""
            
            -- Use pcall for extra safety and try getName from the item
            local success, result = pcall(function()
                if a.item.getName and type(a.item.getName) == "function" then
                    return a.item:getName() or ""
                end
                -- Try getting name from the item type if direct getName fails
                local itemType = g_things.getThingType(a.item:getId(), ThingCategoryItem)
                if itemType and itemType.getName and type(itemType.getName) == "function" then
                    return itemType:getName() or ""
                end
                return ""
            end)
            if success then nameA = result end
            
            success, result = pcall(function()
                if b.item.getName and type(b.item.getName) == "function" then
                    return b.item:getName() or ""
                end
                -- Try getting name from the item type if direct getName fails
                local itemType = g_things.getThingType(b.item:getId(), ThingCategoryItem)
                if itemType and itemType.getName and type(itemType.getName) == "function" then
                    return itemType:getName() or ""
                end
                return ""
            end)
            if success then nameB = result end
            
            return nameA:lower() < nameB:lower() 
        end)
    elseif sortMode == 'sortDescByName' then
        sortWithContainersFirst(items, function(a, b) 
            if not a or not a.item or not b or not b.item then 
                return false 
            end
            
            local nameA = ""
            local nameB = ""
            
            -- Use pcall for extra safety and try getName from the item
            local success, result = pcall(function()
                if a.item.getName and type(a.item.getName) == "function" then
                    return a.item:getName() or ""
                end
                -- Try getting name from the item type if direct getName fails
                local itemType = g_things.getThingType(a.item:getId(), ThingCategoryItem)
                if itemType and itemType.getName and type(itemType.getName) == "function" then
                    return itemType:getName() or ""
                end
                return ""
            end)
            if success then nameA = result end
            
            success, result = pcall(function()
                if b.item.getName and type(b.item.getName) == "function" then
                    return b.item:getName() or ""
                end
                -- Try getting name from the item type if direct getName fails
                local itemType = g_things.getThingType(b.item:getId(), ThingCategoryItem)
                if itemType and itemType.getName and type(itemType.getName) == "function" then
                    return itemType:getName() or ""
                end
                return ""
            end)
            if success then nameB = result end
            
            return nameA:lower() > nameB:lower() 
        end)
    elseif sortMode == 'sortAscByWeight' then
        -- TODO: Implement functionality to retrieve item weights and sort accordingly
        return
    elseif sortMode == 'sortDescByWeight' then
        -- TODO: Implement weight-based sorting (descending)
        return
    elseif sortMode == 'sortAscByExpiry' then
        sortWithContainersFirst(items, function(a, b) 
            if not a or not a.item or not b or not b.item then return false end
            
            local aExpiry = 0
            local bExpiry = 0
            
            -- Use getDurationTime() for expiry - this exists on Item objects
            local success, result = pcall(function()
                if a.item.getDurationTime and type(a.item.getDurationTime) == "function" then
                    return a.item:getDurationTime() or 0
                end
                return 0
            end)
            if success then aExpiry = result end
            
            success, result = pcall(function()
                if b.item.getDurationTime and type(b.item.getDurationTime) == "function" then
                    return b.item:getDurationTime() or 0
                end
                return 0
            end)
            if success then bExpiry = result end
            
            return aExpiry < bExpiry
        end)
    elseif sortMode == 'sortDescByExpiry' then
        sortWithContainersFirst(items, function(a, b) 
            if not a or not a.item or not b or not b.item then return false end
            
            local aExpiry = 0
            local bExpiry = 0
            
            -- Use getDurationTime() for expiry - this exists on Item objects
            local success, result = pcall(function()
                if a.item.getDurationTime and type(a.item.getDurationTime) == "function" then
                    return a.item:getDurationTime() or 0
                end
                return 0
            end)
            if success then aExpiry = result end
            
            success, result = pcall(function()
                if b.item.getDurationTime and type(b.item.getDurationTime) == "function" then
                    return b.item:getDurationTime() or 0
                end
                return 0
            end)
            if success then bExpiry = result end
            
            return aExpiry > bExpiry
        end)
    elseif sortMode == 'sortAscByStackSize' then
        sortWithContainersFirst(items, function(a, b) 
            if not a or not a.item or not b or not b.item then return false end
            
            local countA = 1
            local countB = 1
            local chargesA = 0
            local chargesB = 0
            
            -- Use getCount() - this exists on Item objects
            local success, result = pcall(function()
                if a.item.getCount and type(a.item.getCount) == "function" then
                    return a.item:getCount() or 1
                end
                return 1
            end)
            if success then countA = result end
            
            success, result = pcall(function()
                if b.item.getCount and type(b.item.getCount) == "function" then
                    return b.item:getCount() or 1
                end
                return 1
            end)
            if success then countB = result end
            
            -- Get charges
            success, result = pcall(function()
                if a.item.getCharges and type(a.item.getCharges) == "function" then
                    return a.item:getCharges() or 0
                end
                return 0
            end)
            if success then chargesA = result end
            
            success, result = pcall(function()
                if b.item.getCharges and type(b.item.getCharges) == "function" then
                    return b.item:getCharges() or 0
                end
                return 0
            end)
            if success then chargesB = result end
            
            -- Use charges if available, otherwise use count
            local valueA = chargesA > 0 and chargesA or countA
            local valueB = chargesB > 0 and chargesB or countB
            
            return valueA < valueB 
        end)
    elseif sortMode == 'sortDescByStackSize' then
        sortWithContainersFirst(items, function(a, b) 
            if not a or not a.item or not b or not b.item then return false end
            
            local countA = 1
            local countB = 1
            local chargesA = 0
            local chargesB = 0
            
            -- Use getCount() - this exists on Item objects
            local success, result = pcall(function()
                if a.item.getCount and type(a.item.getCount) == "function" then
                    return a.item:getCount() or 1
                end
                return 1
            end)
            if success then countA = result end
            
            success, result = pcall(function()
                if b.item.getCount and type(b.item.getCount) == "function" then
                    return b.item:getCount() or 1
                end
                return 1
            end)
            if success then countB = result end
            
            -- Get charges
            success, result = pcall(function()
                if a.item.getCharges and type(a.item.getCharges) == "function" then
                    return a.item:getCharges() or 0
                end
                return 0
            end)
            if success then chargesA = result end
            
            success, result = pcall(function()
                if b.item.getCharges and type(b.item.getCharges) == "function" then
                    return b.item:getCharges() or 0
                end
                return 0
            end)
            if success then chargesB = result end
            
            -- Use charges if available, otherwise use count
            local valueA = chargesA > 0 and chargesA or countA
            local valueB = chargesB > 0 and chargesB or countB
            
            return valueA > valueB 
        end)
    else
        -- No sorting or unknown mode
        return
    end
    
    -- Clear all item widgets first
    for slot = 0, totalCapacity - 1 do
        local itemWidget = container.itemsPanel:getChildById('item' .. slot)
        if itemWidget then
            itemWidget:setItem(nil)
        end
    end
    
    -- Place sorted items back into the container display starting from slot 0
    for i, itemData in ipairs(items) do
        local targetSlot = i - 1 -- Convert to 0-based index
        
        if targetSlot < totalCapacity then
            local itemWidget = container.itemsPanel:getChildById('item' .. targetSlot)
            if itemWidget then
                -- Set the visual item (this doesn't change the actual container data)
                itemWidget:setItem(itemData.item)
                -- Preserve the original slot position for drag-and-drop operations
                itemWidget.position = container:getSlotPosition(itemData.slot)
                
                ItemsDatabase.setRarityItem(itemWidget, itemData.item)
                ItemsDatabase.setTier(itemWidget, itemData.item)
                itemWidget:setShowDuration(g_game.getFeature(GameThingClock) and modules.client_options.getOption('showExpiryInContainers'))
                itemWidget:setShowCharges(g_game.getFeature(GameThingCounter) and modules.client_options.getOption('showExpiryInContainers'))

                local itemName = "unnamed"
                local success, result = pcall(function()
                    if itemData.item.getName and type(itemData.item.getName) == "function" then
                        return itemData.item:getName() or "unnamed"
                    end
                    -- Try getting name from the item type if direct getName fails
                    local itemType = g_things.getThingType(itemData.item:getId(), ThingCategoryItem)
                    if itemType and itemType.getName and type(itemType.getName) == "function" then
                        return itemType:getName() or "unnamed"
                    end
                    return "unnamed"
                end)
                if success then itemName = result end
            else
            end
        else
        end
    end
end

-- Function to determine quick loot category for an item

function onContainersMenuAction(actionId)
    local isToggleOption = actionId == 'sortContainersFirst' or actionId == 'sortNestedContainers' or 
                          actionId == 'useManualSortMode' or actionId == 'moveNestedContainers'
    local isActionButton = actionId == 'moveToObtainContainers' or actionId:find('sortAsc') or actionId:find('sortDesc')
    if isActionButton then
        -- Handle action buttons (non-toggle actions)
        if actionId == 'moveToObtainContainers' then
            -- TODO: Need to create function to use quickloot sorting.
            return
        elseif actionId:find('sortAsc') or actionId:find('sortDesc') then
            -- When a sorting action is selected, automatically disable manual sort mode
            local isManualSortEnabled = containerSettings and containerSettings['useManualSortMode'] == 1
            if isManualSortEnabled then
                containerSettings['useManualSortMode'] = 0
            end
            
            -- Sorting actions - these are mutually exclusive
            containerSettings['currentSortMode'] = actionId
            g_settings.setNode('containers', containerSettings)
            
            -- Apply sorting to all open containers
            for _, container in pairs(g_game.getContainers()) do
                if container.window and container.window:isVisible() then
                    sortContainerItems(container, actionId)
                end
            end
            return
        end
    end
    
    if isToggleOption then
        -- Toggle options
        local currentState = getContainerOptionState(actionId)
        local newState = not currentState
        
        -- Special handling for useManualSortMode
        if actionId == 'useManualSortMode' then
            if newState then
                -- When enabling manual sort mode, clear any active sorting mode and disable other sorting options
                containerSettings['currentSortMode'] = 'none'
                containerSettings['sortContainersFirst'] = 0
                containerSettings['sortNestedContainers'] = 0
            else
                -- When disabling manual sort mode, sorting options become available again
            end
        elseif actionId == 'sortContainersFirst' then
            -- Prevent enabling if manual sort mode is active
            local isManualSortEnabled = containerSettings and containerSettings['useManualSortMode'] == 1
            if newState and isManualSortEnabled then
                return -- Don't change the setting
            end
            
            -- When Sort Containers First is toggled, re-apply current sorting if active
            local currentSortMode = containerSettings and containerSettings['currentSortMode']
            if currentSortMode and currentSortMode ~= 'none' then
                -- Apply sorting to all open containers after toggling
                scheduleEvent(function()
                    for _, container in pairs(g_game.getContainers()) do
                        if container.window and container.window:isVisible() then
                            sortContainerItems(container, currentSortMode)
                        end
                    end
                end, 50) -- Small delay to ensure setting is saved first
            end
        elseif actionId == 'sortNestedContainers' then
            -- Prevent enabling if manual sort mode is active
            local isManualSortEnabled = containerSettings and containerSettings['useManualSortMode'] == 1
            if newState and isManualSortEnabled then
                return -- Don't change the setting
            end
            
            -- When Sort Nested Containers is toggled, re-apply current sorting if active
            local currentSortMode = containerSettings and containerSettings['currentSortMode']
            if currentSortMode and currentSortMode ~= 'none' then
                -- Apply sorting to all open containers after toggling
                scheduleEvent(function()
                    for _, container in pairs(g_game.getContainers()) do
                        if container.window and container.window:isVisible() then
                            sortContainerItems(container, currentSortMode)
                        end
                    end
                end, 50) -- Small delay to ensure setting is saved first
            end
        elseif actionId == 'moveNestedContainers' then
            -- TODO: Implement functionality to automatically move nested containers (containers with items inside)
            -- to specific locations or positions within containers. This feature should work in conjunction
            -- with container sorting and could help organize containers by moving filled containers to
            -- preferred positions (e.g., top of container, specific slots, etc.).
            -- Implementation should consider:
            -- 1. Identify containers that have items inside (nested containers)
            -- 2. Define target positions/rules for where to move them
            -- 3. Handle conflicts with existing sorting modes
            -- 4. Respect manual sort mode settings
            -- 5. Provide user feedback on move operations
            
            -- For now, just toggle the setting - actual move functionality to be implemented
        end
        
        -- Save the new state to settings
        containerSettings[actionId] = newState and 1 or 0
        g_settings.setNode('containers', containerSettings)
    end
end

function refreshContainerItems(container)
    -- Check if we should preserve sorting during refresh
    local currentSortMode = containerSettings and containerSettings['currentSortMode']
    local isManualSortEnabled = containerSettings and containerSettings['useManualSortMode'] == 1
    local shouldSort = currentSortMode and currentSortMode ~= 'none' and not isManualSortEnabled
    
    for slot = 0, container:getCapacity() - 1 do
        local itemWidget = container.itemsPanel:getChildById('item' .. slot)
        itemWidget:setItem(container:getItem(slot))
        ItemsDatabase.setRarityItem(itemWidget, container:getItem(slot))
        ItemsDatabase.setTier(itemWidget, container:getItem(slot))
        itemWidget:setShowDuration(g_game.getFeature(GameThingClock) and modules.client_options.getOption('showExpiryInContainers'))
        itemWidget:setShowCharges(g_game.getFeature(GameThingCounter) and modules.client_options.getOption('showExpiryInContainers'))
    end

    if container:hasPages() then
        refreshContainerPages(container)
    end
    
    -- Apply current sorting if one is set and manual sort mode is disabled
    if shouldSort then
        sortContainerItems(container, currentSortMode)
    end
end

function toggleContainerPages(containerWindow, pages)
    local scrollbar = containerWindow:getChildById('miniwindowScrollBar')
    local pagePanel = containerWindow:getChildById('pagePanel')
    local separator = containerWindow:getChildById('separator')
    local contentsPanel = containerWindow:getChildById('contentsPanel')
    local upButton = containerWindow:getChildById('upButton')
    local contextMenuButton = containerWindow:recursiveGetChildById('contextMenuButton')
    local lockButton = containerWindow:recursiveGetChildById('lockButton')
    local minimizeButton = containerWindow:recursiveGetChildById('minimizeButton')
    
    if pages then
        -- When pages are visible, anchor scrollbar to close button bottom and separator top
        scrollbar:breakAnchors()
        scrollbar:addAnchor(AnchorTop, 'closeButton', AnchorBottom)
        scrollbar:addAnchor(AnchorRight, 'parent', AnchorRight)
        scrollbar:addAnchor(AnchorBottom, 'separator', AnchorTop)
        scrollbar:setMarginTop(2)  -- Small margin from close button
        scrollbar:setMarginRight(3)
        scrollbar:setMarginBottom(2)
        
        -- Content panel anchors to separator when pages are visible
        contentsPanel:breakAnchors()
        contentsPanel:addAnchor(AnchorTop, 'miniwindowTopBar', AnchorBottom)
        contentsPanel:addAnchor(AnchorLeft, 'parent', AnchorLeft)
        contentsPanel:addAnchor(AnchorRight, 'miniwindowScrollBar', AnchorLeft)
        contentsPanel:addAnchor(AnchorBottom, 'separator', AnchorTop)
        contentsPanel:setMarginLeft(3)
        contentsPanel:setMarginBottom(1)
        contentsPanel:setMarginTop(-2)
        contentsPanel:setMarginRight(1)
        
        -- When pages are active, move upButton to toggleFilterButton position if it's visible
        if upButton and upButton:isVisible() and contextMenuButton and minimizeButton then
            -- Position upButton where toggleFilterButton was
            upButton:breakAnchors()
            upButton:addAnchor(AnchorTop, minimizeButton:getId(), AnchorTop)
            upButton:addAnchor(AnchorRight, minimizeButton:getId(), AnchorLeft)
            upButton:setMarginRight(7)
            upButton:setMarginTop(0)
            
            -- Move contextMenuButton to the left of upButton
            contextMenuButton:breakAnchors()
            contextMenuButton:addAnchor(AnchorTop, upButton:getId(), AnchorTop)
            contextMenuButton:addAnchor(AnchorRight, upButton:getId(), AnchorLeft)
            contextMenuButton:setMarginRight(2)
            contextMenuButton:setMarginTop(0)
            
            -- Position lockButton to the left of contextMenu
            if lockButton then
                lockButton:breakAnchors()
                lockButton:addAnchor(AnchorTop, contextMenuButton:getId(), AnchorTop)
                lockButton:addAnchor(AnchorRight, contextMenuButton:getId(), AnchorLeft)
                lockButton:setMarginRight(2)
                lockButton:setMarginTop(0)
            end
        end
    else
        -- When pages are hidden, use normal bottom anchor
        scrollbar:breakAnchors()
        scrollbar:addAnchor(AnchorTop, 'parent', AnchorTop)
        scrollbar:addAnchor(AnchorRight, 'parent', AnchorRight)
        scrollbar:addAnchor(AnchorBottom, 'parent', AnchorBottom)
        scrollbar:setMarginTop(16)
        scrollbar:setMarginRight(3)
        scrollbar:setMarginBottom(3)
        
        -- Content panel extends to bottom when pages are hidden
        contentsPanel:breakAnchors()
        contentsPanel:addAnchor(AnchorTop, 'miniwindowTopBar', AnchorBottom)
        contentsPanel:addAnchor(AnchorLeft, 'parent', AnchorLeft)
        contentsPanel:addAnchor(AnchorRight, 'miniwindowScrollBar', AnchorLeft)
        contentsPanel:addAnchor(AnchorBottom, 'parent', AnchorBottom)
        contentsPanel:setMarginLeft(3)
        contentsPanel:setMarginBottom(3)
        contentsPanel:setMarginTop(-2)
        contentsPanel:setMarginRight(1)
        
        -- When pages are not active, reset button positions based on upButton visibility
        if upButton and contextMenuButton and minimizeButton then
            if upButton:isVisible() then
                -- Reset upButton to original position
                upButton:breakAnchors()
                upButton:addAnchor(AnchorTop, minimizeButton:getId(), AnchorTop)
                upButton:addAnchor(AnchorRight, minimizeButton:getId(), AnchorLeft)
                upButton:setMarginRight(3)
                upButton:setMarginTop(0)
                
                -- Position contextMenuButton to the left of upButton
                contextMenuButton:breakAnchors()
                contextMenuButton:addAnchor(AnchorTop, upButton:getId(), AnchorTop)
                contextMenuButton:addAnchor(AnchorRight, upButton:getId(), AnchorLeft)
                contextMenuButton:setMarginRight(2)
                contextMenuButton:setMarginTop(0)
            else
                -- Position contextMenuButton where toggleFilterButton was
                contextMenuButton:breakAnchors()
                contextMenuButton:addAnchor(AnchorTop, minimizeButton:getId(), AnchorTop)
                contextMenuButton:addAnchor(AnchorRight, minimizeButton:getId(), AnchorLeft)
                contextMenuButton:setMarginRight(7)
                contextMenuButton:setMarginTop(0)
            end
            
            -- Position lockButton to the left of contextMenu
            if lockButton then
                lockButton:breakAnchors()
                lockButton:addAnchor(AnchorTop, contextMenuButton:getId(), AnchorTop)
                lockButton:addAnchor(AnchorRight, contextMenuButton:getId(), AnchorLeft)
                lockButton:setMarginRight(2)
                lockButton:setMarginTop(0)
            end
        end
    end
    
    pagePanel:setVisible(pages)
    separator:setVisible(pages)
end

function refreshContainerPages(container)
    local currentPage = 1 + math.floor(container:getFirstIndex() / container:getCapacity())
    local pages = 1 + math.floor(math.max(0, (container:getSize() - 1)) / container:getCapacity())
    container.window:recursiveGetChildById('pageLabel'):setText(string.format('Page %i of %i', currentPage, pages))

    local prevPageButton = container.window:recursiveGetChildById('prevPageButton')
    local nextPageButton = container.window:recursiveGetChildById('nextPageButton')
    
    -- If there's only one page, hide both navigation buttons
    if pages == 1 then
        prevPageButton:setVisible(false)
        nextPageButton:setVisible(false)
    else
        -- Multiple pages logic
        if currentPage == 1 then
            -- Hide the back button when on the first page of multiple pages
            prevPageButton:setVisible(false)
        else
            prevPageButton:setVisible(true)
            prevPageButton:setEnabled(true)
            prevPageButton.onClick = function()
                -- Store current height before page change
                local currentHeight = container.window:getHeight()
                container.window.preservedHeight = currentHeight
                g_game.seekInContainer(container:getId(), container:getFirstIndex() - container:getCapacity())
            end
        end

        if currentPage >= pages then
            nextPageButton:setVisible(false)
        else
            nextPageButton:setVisible(true)
            nextPageButton:setEnabled(true)
            nextPageButton.onClick = function()
                -- Store current height before page change
                local currentHeight = container.window:getHeight()
                container.window.preservedHeight = currentHeight
                g_game.seekInContainer(container:getId(), container:getFirstIndex() + container:getCapacity())
            end
        end
    end
end

function onContainerOpen(container, previousContainer)
    local containerWindow
    if previousContainer then
        containerWindow = previousContainer.window
        previousContainer.window = nil
        previousContainer.itemsPanel = nil
    else
        containerWindow = g_ui.createWidget('ContainerWindow')
    end
    containerWindow:setId('container' .. container:getId())
    local containerPanel = containerWindow:getChildById('contentsPanel')
    local containerItemWidget = containerWindow:getChildById('containerItemWidget')
    containerWindow.onClose = function()
        g_game.close(container)
        containerWindow:hide()
    end

    -- this disables scrollbar auto hiding
    local scrollbar = containerWindow:getChildById('miniwindowScrollBar')
    scrollbar:mergeStyle({
        ['$!on'] = {}
    })
    
    -- Scrollbar positioning will be handled by toggleContainerPages function

    local upButton = containerWindow:getChildById('upButton')
    upButton.onClick = function()
        g_game.openParent(container)
    end
    upButton:setVisible(container:hasParent())

    -- Add minimize/maximize event handlers to manage pagePanel visibility
    containerWindow.onMinimize = function()
        local pagePanel = containerWindow:getChildById('pagePanel')
        if pagePanel and pagePanel:isVisible() then
            pagePanel.wasVisibleBeforeMinimize = true
            pagePanel:setVisible(false)
        end
    end
    
    containerWindow.onMaximize = function()
        local pagePanel = containerWindow:getChildById('pagePanel')
        if pagePanel and pagePanel.wasVisibleBeforeMinimize then
            pagePanel:setVisible(true)
            pagePanel.wasVisibleBeforeMinimize = nil
        end
    end

    -- Hide toggleFilterButton and adjust button positioning
    local toggleFilterButton = containerWindow:recursiveGetChildById('toggleFilterButton')
    if toggleFilterButton then
        toggleFilterButton:setVisible(false)
        toggleFilterButton:setOn(false)
    end
    
    -- Hide newWindowButton
    local newWindowButton = containerWindow:recursiveGetChildById('newWindowButton')
    if newWindowButton then
        newWindowButton:setVisible(false)
    end
    
    local contextMenuButton = containerWindow:recursiveGetChildById('contextMenuButton')
    local lockButton = containerWindow:recursiveGetChildById('lockButton')
    local minimizeButton = containerWindow:recursiveGetChildById('minimizeButton')
    
    -- Make sure contextMenuButton is visible
    if contextMenuButton then
        contextMenuButton:setVisible(true)
    end
    
    if contextMenuButton and minimizeButton then
        if container:hasParent() then
            -- When upButton is visible, position contextMenuButton to its left
            contextMenuButton:breakAnchors()
            contextMenuButton:addAnchor(AnchorTop, upButton:getId(), AnchorTop)
            contextMenuButton:addAnchor(AnchorRight, upButton:getId(), AnchorLeft)
            contextMenuButton:setMarginRight(2)
            contextMenuButton:setMarginTop(0)
        else
            -- When upButton is not visible, position contextMenuButton where toggleFilterButton was
            contextMenuButton:breakAnchors()
            contextMenuButton:addAnchor(AnchorTop, minimizeButton:getId(), AnchorTop)
            contextMenuButton:addAnchor(AnchorRight, minimizeButton:getId(), AnchorLeft)
            contextMenuButton:setMarginRight(7)
            contextMenuButton:setMarginTop(0)
        end
        
        -- Position lockButton to the left of contextMenu
        if lockButton then
            lockButton:breakAnchors()
            lockButton:addAnchor(AnchorTop, contextMenuButton:getId(), AnchorTop)
            lockButton:addAnchor(AnchorRight, contextMenuButton:getId(), AnchorLeft)
            lockButton:setMarginRight(2)
            lockButton:setMarginTop(0)
        end
        
        -- Add onClick handler for context menu
        contextMenuButton.onClick = function(widget, mousePos, mouseButton)
            return showContainersContextMenu(widget, mousePos, mouseButton)
        end
    end

    local name = container:getName()
    name = name:sub(1, 1):upper() .. name:sub(2)

    if name:len() > 14 then
        name = name:sub(1, 14) .. "..."
    end

    -- Set the title in the new miniwindowTitle element
    local titleWidget = containerWindow:getChildById('miniwindowTitle')
    if titleWidget then
        titleWidget:setText(name)
    else
        -- Fallback to old method if miniwindowTitle doesn't exist
        containerWindow:setText(name)
    end

    containerItemWidget:setItem(container:getContainerItem())
    containerItemWidget:setPhantom(true)

    containerPanel:destroyChildren()
    for slot = 0, container:getCapacity() - 1 do
        local itemWidget = g_ui.createWidget('Item', containerPanel)
        itemWidget:setId('item' .. slot)
        itemWidget:setItem(container:getItem(slot))
        ItemsDatabase.setRarityItem(itemWidget, container:getItem(slot))
        ItemsDatabase.setTier(itemWidget, container:getItem(slot))
        itemWidget:setShowDuration(g_game.getFeature(GameThingClock) and modules.client_options.getOption('showExpiryInContainers'))
        itemWidget:setShowCharges(g_game.getFeature(GameThingCounter) and modules.client_options.getOption('showExpiryInContainers'))
        itemWidget:setMargin(0)
        itemWidget.position = container:getSlotPosition(slot)

        if not container:isUnlocked() then
            itemWidget:setBorderColor('red')
        end
    end

    container.window = containerWindow
    container.itemsPanel = containerPanel

    toggleContainerPages(containerWindow, container:hasPages())
    refreshContainerPages(container)

    local layout = containerPanel:getLayout()
    local cellSize = layout:getCellSize()
    local step = cellSize.height + layout:getCellSpacing()
    local numLines = math.max(layout:getNumLines(), 1)
    local chromeHeight = container:hasPages() and 55 or 31
    containerWindow:setContentMinimumHeight(cellSize.height)

    local resizeBorder = containerWindow:getChildById('bottomResizeBorder')
    if resizeBorder then
        resizeBorder:setMinimum(step + chromeHeight)
        resizeBorder:setMaximum(numLines * step + chromeHeight)
    end
    -- Enables dragging only when mouse press occurs within window bounds (with tolerance margins)
    -- and not over the containerPanel child widget
    -- On Drop: When an item is dropped, it is placed at the nearest valid parent location, such as in a grid.
    local TOLERANCE_HORIZONTAL = 5
    local TOLERANCE_VERTICAL = 2
    containerWindow.onMousePress = function(widget, mousePos, mouseButton)
        if mouseButton ~= MouseLeftButton then
            return false
        end
        local winX, winY = containerWindow:getX(), containerWindow:getY()
        local winW, winH = containerWindow:getWidth(), containerWindow:getHeight()
        local inBounds = mousePos.x >= winX + TOLERANCE_HORIZONTAL and 
                        mousePos.x <= winX + winW - TOLERANCE_HORIZONTAL and
                        mousePos.y >= winY + TOLERANCE_VERTICAL and 
                        mousePos.y <= winY + winH - TOLERANCE_VERTICAL
        containerWindow:setDraggable(inBounds and containerWindow:getChildByPos(mousePos) ~= containerPanel)
        return inBounds
    end
    containerWindow.onMouseRelease = function(widget, mousePos, mouseButton)
        containerWindow:setDraggable(true)
    end
    containerWindow.onDrop = function(container, widget, mousePos)
        if containerPanel:getChildByPos(mousePos) then
            return false
        end
        local child = containerPanel:getNearestChild(mousePos)
        if child then
            child:onDrop(widget, mousePos, true)
        end
    end

    if not previousContainer then
        local panel = modules.game_interface.findContentPanelAvailable(containerWindow, cellSize.height)
        panel:addChild(containerWindow)
    end

    if not previousContainer or previousContainer:getCapacity() >= container:getCapacity() then
        -- Always set the content height based on the current container's content, with a minimum of one row
        local minRows = 1
        if modules.client_options.getOption('openMaximized') then
            local numLines = math.max(layout:getNumLines(), minRows)
            containerWindow:setContentHeight(numLines * step + chromeHeight)
        else
            local numColumns = math.max(layout:getNumColumns(), 1)
            local filledLines = math.max(math.ceil(container:getItemsCount() / numColumns), minRows)
            containerWindow:setContentHeight(filledLines * step + chromeHeight)
        end
    end

    containerWindow:setup()
    
    -- Apply current sorting mode if one is active and manual sort mode is disabled
    local currentSortMode = containerSettings and containerSettings['currentSortMode']
    local isManualSortEnabled = containerSettings and containerSettings['useManualSortMode'] == 1
    if currentSortMode and currentSortMode ~= 'none' and not isManualSortEnabled then
        sortContainerItems(container, currentSortMode)
    end
end

function onContainerClose(container)
    destroy(container)
end

function onContainerChangeSize(container, size)
    if not container.window then
        return
    end
    
    -- Store the current height if one was preserved from page navigation
    local preservedHeight = container.window.preservedHeight
    
    refreshContainerItems(container)
    
    -- Restore the preserved height if it exists (from page switching)
    if preservedHeight then
        container.window:setHeight(preservedHeight)
        container.window.preservedHeight = nil -- Clear the preserved height
    end
end

function onContainerUpdateItem(container, slot, item, oldItem)
    if not container.window then
        return
    end
    local itemWidget = container.itemsPanel:getChildById('item' .. slot)
    itemWidget:setItem(item)
    itemWidget:setShowDuration(g_game.getFeature(GameThingClock) and modules.client_options.getOption('showExpiryInContainers'))
    itemWidget:setShowCharges(g_game.getFeature(GameThingCounter) and modules.client_options.getOption('showExpiryInContainers'))
    
    -- Note: Removed automatic re-sorting to prevent interference with manual item movement
    -- Sorting should only happen when explicitly requested by the user
end
