-- Turtle Logistics System v4.1 (Optimized)
-- Supports direct container-to-container transfers
-- Config saved in config.cfg

local configFile = "config.cfg"
local tasks = {}
local turtleName = "turtle_" .. os.getComputerID() -- Default name
local directions = {
    up = "up", down = "down", forward = "forward"
}

-- Load configuration
local function loadConfig()
    if fs.exists(configFile) then
        local file = fs.open(configFile, "r")
        local data = file.readAll()
        file.close()
        tasks = textutils.unserialize(data) or {}
    end
    
    -- Load turtle name if set
    if fs.exists("turtle_name.cfg") then
        local nameFile = fs.open("turtle_name.cfg", "r")
        turtleName = nameFile.readAll()
        nameFile.close()
    end
end

-- Save configuration
local function saveConfig()
    local file = fs.open(configFile, "w")
    file.write(textutils.serialize(tasks))
    file.close()
end

-- Save turtle name
local function saveTurtleName()
    local nameFile = fs.open("turtle_name.cfg", "w")
    nameFile.write(turtleName)
    nameFile.close()
end

-- Check if value is a direction
local function isDirection(value)
    return directions[value] ~= nil
end

-- Parse item requirements from string
local function parseItemRequirements(input)
    local requirements = {}
    
    -- Check if input is a JSON-like table
    if input:sub(1,1) == "{" and input:sub(-1) == "}" then
        -- Remove curly braces
        local content = input:sub(2, -2)
        
        -- Split key-value pairs
        for pair in content:gmatch("[^,]+") do
            local key, value = pair:match("[\"']?(.-)[\"']?%s*:%s*(%d+)")
            if key and value then
                requirements[key] = tonumber(value)
            end
        end
    else
        -- Simple format: item:minCount
        for item in input:gmatch("%S+") do
            local name, minCount = item:match("([^:]+):(%d+)")
            if name and minCount then
                requirements[name] = tonumber(minCount)
            else
                requirements[item] = 0 -- No minimum requirement
            end
        end
    end
    
    return requirements
end

-- Get container item list using container.list()
local function getContainerItems(containerName)
    local container = peripheral.wrap(containerName)
    if not container then return nil end
    
    local items = {}
    local containerList = container.list()
    
    for slot, item in pairs(containerList) do
        items[slot] = {
            count = item.count,
            name = item.name
        }
    end
    
    return items
end

-- Execute item transfer with min count requirements (Optimized)
local function executeTransfer(task)
    -- Case 1: Both source and destination are containers
    if not isDirection(task.source) and not isDirection(task.destination) then
        local source = peripheral.wrap(task.source)
        local destination = peripheral.wrap(task.destination)
        
        if not source or not destination then
            if not source then print("Error: Source container not found: "..task.source) end
            if not destination then print("Error: Destination container not found: "..task.destination) end
            return false
        end
        
        -- Get destination name for pushItems
        local destName = peripheral.getName(destination)
        
        -- Check min count requirements
        if task.items then
            local sourceItems = getContainerItems(task.source)
            local itemCounts = {}
            
            for slot, item in pairs(sourceItems) do
                if task.items[item.name] then
                    itemCounts[item.name] = (itemCounts[item.name] or 0) + item.count
                end
            end
            
            for itemName, minCount in pairs(task.items) do
                if minCount > 0 and (itemCounts[itemName] or 0) < minCount then
                    print("Not enough "..itemName.." ("..(itemCounts[itemName] or 0).." < "..minCount..")")
                    return false
                end
            end
        end
        
        -- Transfer items directly
        local sourceItems = getContainerItems(task.source)
        local totalTransferred = 0
        
        for slot, item in pairs(sourceItems) do
            local shouldTransfer = not task.items or (task.items[item.name] ~= nil)
            
            if shouldTransfer then
                local count = item.count
                if task.items and task.items[item.name] then
                    count = math.min(count, task.items[item.name])
                end
                
                local transferred = source.pushItems(destName, slot, count)
                totalTransferred = totalTransferred + transferred
            end
        end
        
        return totalTransferred > 0
    
    -- Case 2: Source is direction, destination is container
    elseif isDirection(task.source) and not isDirection(task.destination) then
        local destination = peripheral.wrap(task.destination)
        if not destination then
            print("Error: Destination container not found: "..task.destination)
            return false
        end
        
        -- Suck items from direction (limited to 16 slots)
        local sucked = false
        local suckFunc = turtle.suck
        if task.source == "up" then suckFunc = turtle.suckUp
        elseif task.source == "down" then suckFunc = turtle.suckDown end
        
        for i = 1, 16 do
            if suckFunc() then
                sucked = true
            else
                break
            end
        end
        
        if not sucked then return false end
        
        -- Push items to destination container
        local pushed = false
        for slot = 1, 16 do
            if turtle.getItemCount(slot) > 0 then
                if destination.pullItems(turtleName, slot) > 0 then
                    pushed = true
                end
            end
        end
        
        return pushed
    
    -- Case 3: Source is container, destination is direction
    elseif not isDirection(task.source) and isDirection(task.destination) then
        local source = peripheral.wrap(task.source)
        if not source then
            print("Error: Source container not found: "..task.source)
            return false
        end
        
        -- Check min count requirements
        if task.items then
            local sourceItems = getContainerItems(task.source)
            local itemCounts = {}
            
            for slot, item in pairs(sourceItems) do
                if task.items[item.name] then
                    itemCounts[item.name] = (itemCounts[item.name] or 0) + item.count
                end
            end
            
            for itemName, minCount in pairs(task.items) do
                if minCount > 0 and (itemCounts[itemName] or 0) < minCount then
                    print("Not enough "..itemName.." ("..(itemCounts[itemName] or 0).." < "..minCount..")")
                    return false
                end
            end
        end
        
        -- Pull items to turtle
        local sourceItems = getContainerItems(task.source)
        local pulled = false
        
        for slot, item in pairs(sourceItems) do
            local shouldTransfer = not task.items or (task.items[item.name] ~= nil)
            
            if shouldTransfer then
                local count = item.count
                if task.items and task.items[item.name] then
                    count = math.min(count, task.items[item.name])
                end
                
                if source.pushItems(turtleName, slot, count) > 0 then
                    pulled = true
                end
            end
        end
        
        if not pulled then return false end
        
        -- Drop items to direction
        local dropFunc = turtle.drop
        if task.destination == "up" then dropFunc = turtle.dropUp
        elseif task.destination == "down" then dropFunc = turtle.dropDown end
        
        local dropped = false
        for slot = 1, 16 do
            if turtle.getItemCount(slot) > 0 then
                turtle.select(slot)
                if dropFunc() then
                    dropped = true
                end
            end
        end
        
        return dropped
    
    -- Case 4: Both source and destination are directions
    else
        -- Suck items from source direction (limited to 16 slots)
        local suckFunc = turtle.suck
        if task.source == "up" then suckFunc = turtle.suckUp
        elseif task.source == "down" then suckFunc = turtle.suckDown end
        
        local sucked = false
        for i = 1, 16 do
            if suckFunc() then
                sucked = true
            else
                break
            end
        end
        
        if not sucked then return false end
        
        -- Drop items to destination direction
        local dropFunc = turtle.drop
        if task.destination == "up" then dropFunc = turtle.dropUp
        elseif task.destination == "down" then dropFunc = turtle.dropDown end
        
        local dropped = false
        for slot = 1, 16 do
            if turtle.getItemCount(slot) > 0 then
                turtle.select(slot)
                if dropFunc() then
                    dropped = true
                end
            end
        end
        
        return dropped
    end
end

-- Main task loop (optimized)
local function taskLoop()
    while true do
        for i, task in ipairs(tasks) do
            local success, err = pcall(executeTransfer, task)
            if not success then
                print("Task "..i.." error: "..err)
            end
        end
        os.sleep(0.5)  -- Slightly longer sleep to reduce CPU usage
    end
end

-- Command processing
local function processCommand(cmd)
    local args = {}
    for word in cmd:gmatch("%S+") do
        table.insert(args, word)
    end
    
    if #args == 0 then return end
    
    local command = args[1]:lower()
    
    if command == "add" and #args >= 3 then
        local newTask = {
            source = args[2],
            destination = args[3],
            items = nil
        }
        
        -- Parse item requirements
        if #args > 3 then
            local itemsInput = table.concat(args, " ", 4)
            newTask.items = parseItemRequirements(itemsInput)
        end
        
        table.insert(tasks, newTask)
        saveConfig()
        print("Task added: "..newTask.source.." -> "..newTask.destination)
        
    elseif command == "list" then
        if #tasks == 0 then
            print("No tasks configured")
        else
            for i, task in ipairs(tasks) do
                local itemInfo = ""
                if task.items then
                    local itemsList = {}
                    for name, minCount in pairs(task.items) do
                        if minCount > 0 then
                            table.insert(itemsList, name..":"..minCount)
                        else
                            table.insert(itemsList, name)
                        end
                    end
                    itemInfo = " ("..table.concat(itemsList, ", ")..")"
                end
                print("["..i.."] "..task.source.." -> "..task.destination..itemInfo)
            end
        end
        
    elseif command == "remove" and #args >= 2 then
        local index = tonumber(args[2])
        if index and tasks[index] then
            table.remove(tasks, index)
            saveConfig()
            print("Task "..index.." removed")
        else
            print("Invalid task index")
        end
        
    elseif command == "setname" and #args >= 2 then
        turtleName = args[2]
        saveTurtleName()
        print("Turtle name set to: "..turtleName)
        
    elseif command == "help" then
        print("Available commands:")
        print("add <source> <destination> [items] - Add transfer task")
        print("  Items format:")
        print("    Simple: item1[:minCount] item2[:minCount] ...")
        print("    JSON-like: {\"item1\":minCount, \"item2\":minCount}")
        print("list - List all tasks")
        print("remove <index> - Remove task")
        print("setname <name> - Set turtle peripheral name")
        print("exit - Exit program")
        
    elseif command == "exit" then
        print("Exiting program")
        os.sleep(0.5)
        error("Program terminated", 0)
    end
end

-- Initialize
loadConfig()
print("Turtle Logistics System started. Type 'help' for commands.")
print("Current turtle name: "..turtleName)

-- Main loop
parallel.waitForAll(
    function()
        while true do
            write("> ")
            local command = read()
            processCommand(command)
        end
    end,
    taskLoop
)