-- Turtle Logistics System v4.3 (Silent Mode & Full Transfer)
-- Supports direct container-to-container transfers for items and fluids
-- 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
            -- 支持JSON格式: "key":value
            local key, value = pair:match("[\"']?(.-)[\"']?%s*:%s*(%d+)")
            if key and value then
                requirements[key] = tonumber(value)
            end
        end
    else
        -- 只支持等号格式: item=count
        for item in input:gmatch("%S+") do
            -- 匹配等号格式: modid:itemid=count
            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

-- Parse fluid requirements from string
local function parseFluidRequirements(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
            -- 支持JSON格式: "key":value
            local key, value = pair:match("[\"']?(.-)[\"']?%s*:%s*(%d+)")
            if key and value then
                requirements[key] = tonumber(value)
            end
        end
    else
        -- 只支持等号格式: fluid=minAmount
        for fluid in input:gmatch("%S+") do
            -- 匹配等号格式: fluid_name=minAmount
            local name, minAmount = fluid:match("([^=]+)=(%d+)")
            
            -- 如果匹配到等号格式
            if name and minAmount then
                requirements[name] = tonumber(minAmount)
            else
                -- 没有等号，视为只有流体名
                requirements[fluid] = 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

-- Get fluid tank contents
local function getFluidTanks(containerName)
    local container = peripheral.wrap(containerName)
    if not container then return nil end
    
    if not container.tanks then
        print("Error: Container does not support fluids: "..containerName)
        return nil
    end
    
    return container.tanks()
end

-- Execute fluid transfer between containers
local function executeFluidTransfer(task)
    -- Both source and destination must be containers for fluid transfers
    if isDirection(task.source) or isDirection(task.destination) then
        print("Error: Fluid transfers require container-to-container transfers")
        return false
    end
    
    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
    
    if not source.tanks or not destination.tanks then
        print("Error: One or both containers do not support fluids")
        return false
    end
    
    -- Check min amount requirements (only if minAmount > 0)
    if task.fluids then
        local sourceTanks = getFluidTanks(task.source)
        if not sourceTanks then return false end
        
        local fluidAmounts = {}
        for slot, tank in pairs(sourceTanks) do
            if tank.name and task.fluids[tank.name] then
                fluidAmounts[tank.name] = (fluidAmounts[tank.name] or 0) + tank.amount
            end
        end
        
        for fluidName, minAmount in pairs(task.fluids) do
            -- Only check if minAmount > 0
            if minAmount > 0 and (fluidAmounts[fluidName] or 0) < minAmount then
                return false
            end
        end
    end
    
    -- Transfer fluids
    local sourceTanks = getFluidTanks(task.source)
    if not sourceTanks then return false end
    
    local totalTransferred = 0
    
    for slot, tank in pairs(sourceTanks) do
        local shouldTransfer = not task.fluids or (task.fluids[tank.name] ~= nil)
        
        if shouldTransfer and tank.name and tank.amount > 0 then
            local amount = tank.amount
            if task.fluids and task.fluids[tank.name] then
                -- If minAmount is 0, transfer all available
                if task.fluids[tank.name] == 0 then
                    amount = tank.amount
                else
                    amount = math.min(amount, task.fluids[tank.name])
                end
            end
            
            -- Push fluid from source to destination
            local transferred = source.pushFluid(task.destination, amount, tank.name)
            totalTransferred = totalTransferred + transferred
        end
    end
    
    return totalTransferred > 0
end

-- Execute item transfer with min count requirements (Optimized)
local function executeTransfer(task)
    -- Handle fluid transfers separately
    if task.type == "fluid" then
        return executeFluidTransfer(task)
    end
    
    -- 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 (only if minCount > 0)
        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
                -- Only check if minCount > 0
                if minCount > 0 and (itemCounts[itemName] or 0) < minCount then
                    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
                    -- If minCount is 0, transfer all available
                    if task.items[item.name] == 0 then
                        count = item.count
                    else
                        count = math.min(count, task.items[item.name])
                    end
                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 (only if minCount > 0)
        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
                -- Only check if minCount > 0
                if minCount > 0 and (itemCounts[itemName] or 0) < minCount then
                    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
                    -- If minCount is 0, transfer all available
                    if task.items[item.name] == 0 then
                        count = item.count
                    else
                        count = math.min(count, task.items[item.name])
                    end
                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 = {
            type = "item",
            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("Item task added: "..newTask.source.." -> "..newTask.destination)
        
    elseif command == "addfluid" and #args >= 3 then
        local newTask = {
            type = "fluid",
            source = args[2],
            destination = args[3],
            fluids = nil
        }
        
        -- Parse fluid requirements
        if #args > 3 then
            local fluidsInput = table.concat(args, " ", 4)
            newTask.fluids = parseFluidRequirements(fluidsInput)
        end
        
        table.insert(tasks, newTask)
        saveConfig()
        print("Fluid 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
                if task.type == "fluid" then
                    local fluidInfo = ""
                    if task.fluids then
                        local fluidsList = {}
                        for name, minAmount in pairs(task.fluids) do
                            if minAmount > 0 then
                                table.insert(fluidsList, name.."="..minAmount.."mB")
                            else
                                table.insert(fluidsList, name)
                            end
                        end
                        fluidInfo = " ("..table.concat(fluidsList, ", ")..")"
                    end
                    print("[FLUID "..i.."] "..task.source.." -> "..task.destination..fluidInfo)
                else
                    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("[ITEM "..i.."] "..task.source.." -> "..task.destination..itemInfo)
                end
            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 item transfer task")
        print("  Items format:")
        print("    Simple: item1[=minCount] item2[=minCount] ...")
        print("    Set minCount to 0 to transfer all available items")
        print("addfluid <source> <destination> [fluids] - Add fluid transfer task")
        print("  Fluids format:")
        print("    Simple: fluid1[=minAmount] fluid2[:minAmount] ...")
        print("    Set minAmount to 0 to transfer all available fluid")
        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 v4.3 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
)