#! /usr/bin/lua

local nixio = require("nixio")

function capture(cmd)
    local tmpfile = "/tmp/ansible.out"
    local rc = os.execute(cmd .. " > " .. tmpfile .. " 2>&1")
    local output = ""
    local f = io.open(tmpfile, "r")
    if f then
        output = f:read("*a")
        f:close()
        nixio.fs.unlink(tmpfile)
    end
    return rc, output
end

function execute(args)
    local result = { changed = false, failed = false }

    if args.update_cache then
        result.cache_update_time = nixio.fs.stat("/var/opkg-lists/aredn_core", "mtime") or 0
        if result.cache_update_time + (tonumber(args.cache_valid_time) or -1) < os.time() then
            local rc, output = capture("opkg update > /dev/null 2>&1")
            if rc == 0 then
                result.cached_updated = true
                result.cache_update_time = os.time()
            end
        end
    end

    local installed = false
    if args.name then
        local rc, output = capture("opkg list-installed")
        if rc ~= 0 then
            result.failed = true
            return result
        end
        for p in output:gmatch("([^\n]+)")
        do
            local n, v = p:match("^(%S+)%s%-%s(%S+)$")
            if n and v then
                if n .. "_" .. v .. "_all.ipk" == args.name then
                    installed = true
                    break
                end
            end
        end
    end

    if args.state == "present" then
        if not installed or args.reinstall then
            local options = "--force-overwrite "
            if args.allow_downgrade then
                options = options .. "--force-downgrade "
            end
            if args.reinstall then
                options = options .. "--force-reinstall "
            end
            if args.pkg then
                options = options .. args.pkg
            elseif args.name then
                options = options .. args.name
            end
            if args.nowait then
                local pid = nixio.fork()
                if pid == -1 then
                    result.failed = true
                    result.msg = "failed to fork"
                elseif pid == 0 then
                    nixio.setsid() -- Stop ansible killing the child on the way out
                    os.execute("opkg install " .. options)
                    os.exit()
                else
                    result.changed = true
                    result.msg = "installing in background"
                end
            else
                local rc, output = capture("opkg install " .. options)
                if rc == 0 then
                    result.changed = true
                else
                    result.failed = true
                    result.msg = output
                end
            end
        end
    elseif args.state == "absent" then
        if installed then
            local options = ""
            if args.autoremove then
                options = "--autoremove "
            end
            local rc, output = capture("opkg remove " .. options .. args.name)
            if rc == 0 then
                result.changed = true
            else
                result.failed = true
                result.msg = output
            end
        end
    else
        result.failed = true
        result.msg = "Unknown state"
    end

    return result
end

-- Boilerplate below --

local json = require("luci.jsonc")

local success, result = pcall(execute, json.parse([[<<INCLUDE_ANSIBLE_MODULE_JSON_ARGS>>]]))
if not success then
    result = {
        failed = true,
        changed = false,
        msg = result
    }
else
    if result.failed ~= false then
        result.failed = true
    end
    if result.changed ~= false then
        result.changed = true
    end
end
io.write(json.stringify(result))
