#! /usr/bin/lua

local uci = require("uci")

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

    if not args.name then
        result.failed = true
        result.msg = "missing parameter: name"
        return result
    end
    if not args.password then
        result.failed = true
        result.msg = "missing parameter: password"
        return result
    end
    if not args.index then
        result.failed = true
        result.msg = "missing parameter: index"
        return result
    end

    local cursor = uci.cursor()

    if args.dns_name then
        if args.dnsname ~= cursor:get("vtun", "@network[0]", "dns") then
            cursor:set("vtun", "@network[0]", "dns", args.dns_name)
            result.changed = true
        end
    end
    if args.network then
        if not args.network:match("^172%.31%.") then
            result.failed = true
            result.msg = "Bad network prefix"
            return result
        end
        if args.network ~= cursor:get("vtun", "@network[0]", "start") then
            cursor:set("vtun", "@network[0]", "start", args.network)
            result.changed = true
        end
    end

    local client = "client_" .. args.index
    local contact = args.comment or ""
    local enabled = args.enable == false and "0" or "1"
    local ip3, ip4 = cursor:get("vtun", "@network[0]", "start"):match("^(%d+%.%d+%.%d+%.)(%d+)$")
    local name = args.name:upper()
    ip4 = tonumber(ip4) + 4 * tonumber(args.index)
    if ip4 >= 251 then
        result.failed = true
        result.msg = "too many tunnels: " .. args.index
        return result
    end

    if not cursor:get("vtun", client) or
       name ~= cursor:get("vtun", client, "name") or
       args.password ~= cursor:get("vtun", client, "passwd") or
       contact ~= (cursor:get("vtun", client, "contact") or "") or
       enabled ~= cursor:get("vtun", client, "enabled") then
        cursor:set("vtun", client, "name", name)
        cursor:set("vtun", client, "passwd", args.password)
        cursor:set("vtun", client, "contact", contact)
        cursor:set("vtun", client, "enabled", enabled)
        cursor:set("vtun", client, "netip", ip3 .. ip4)
        cursor:set("vtun", client, "clientip", ip3 .. (ip4 + 1))
        cursor:set("vtun", client, "serverip", ip3 .. (ip4 + 2))
        cursor:set("vtun", client, "node", name .. "-" .. (ip3 .. ip4):gsub("%.", "-"))
        result.changed = true
    end

    if result.changed then
        cursor:commit("vtun")
        local r = io.open("/etc/config/vtun", "r")
        if r then
            local w = io.open("/etc/config.mesh/vtun", "w")
            if w then
                w:write(r:read("*a"))
                w:close()
            end
            r:close()
        end
    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))
