#!/usr/bin/lua

local site = require 'gluon.site'
local util = require 'gluon.util'
local vpn_core = require 'gluon.mesh-vpn'

local uci = require('simple-uci').cursor()


local syslog_level = uci:get('fastd', 'mesh_vpn', 'syslog_level') or 'verbose'

local methods

if site.mesh_vpn.fastd.configurable(false) then
	local has_null = util.contains(site.mesh_vpn.fastd.methods(), 'null')

	local old_methods = uci:get('fastd', 'mesh_vpn', 'method')
	if old_methods then
		has_null = util.contains(old_methods, 'null')
	end

	methods = {}
	if has_null then
		table.insert(methods, 'null')
	end

	for _, method in ipairs(site.mesh_vpn.fastd.methods()) do
		if method ~= 'null' then
			table.insert(methods, method)
		end
	end

else
	methods = site.mesh_vpn.fastd.methods()
end


uci:section('fastd', 'fastd', 'mesh_vpn', {
	group = 'gluon-mesh-vpn',
	syslog_level = syslog_level,
	interface = vpn_core.get_interface(),
	mode = 'tap',
	mtu = site.mesh_vpn.mtu(),
	secure_handshakes = true,
	method = methods,
	packet_mark = 1,
	status_socket = '/var/run/fastd.mesh_vpn.socket',
})
uci:delete('fastd', 'mesh_vpn', 'user')


-- Collect list of groups that have peers with 'preserve' flag
local preserve_groups = {}

local function preserve_group(name)
	if not name or preserve_groups[name] then
		return
	end
	preserve_groups[name] = true

	local parent = uci:get('fastd', name, 'group')
	preserve_group(parent)
end

uci:foreach('fastd', 'peer', function(peer)
	if peer.net == 'mesh_vpn' and peer.preserve == '1' then
		preserve_group(peer.group)
	end
end)


-- Clean up previous configuration
uci:delete_all('fastd', 'peer', function(peer)
	return (peer.net == 'mesh_vpn' and peer.preserve ~= '1')
end)
uci:delete_all('fastd', 'peer_group', function(group)
	return (group.net == 'mesh_vpn' and not preserve_groups[group['.name']])
end)


local add_groups

local function add_peer(group, name, config)
	local uci_name = group .. '_peer_' .. name
	if uci:get_bool('fastd', uci_name, 'preserve') then
		return
	end
	uci:section('fastd', 'peer', uci_name, {
		enabled = true,
		net = 'mesh_vpn',
		group = group,
		key = config.key,
		remote = config.remotes,
	})
end

local function add_group(name, config, parent)
	uci:section('fastd', 'peer_group', name, {
		enabled = true,
		net = 'mesh_vpn',
		parent = parent,
		peer_limit = config.limit,
	})

	for peername, peerconfig in pairs(config.peers or {}) do
		add_peer(name, peername, peerconfig)
	end

	add_groups(name, config.groups, name)
end

-- declared local above
function add_groups(prefix, groups, parent)
	for name, group in pairs(groups or {}) do
		add_group(prefix .. '_' .. name, group, parent)
	end
end

add_groups('mesh_vpn', site.mesh_vpn.fastd.groups())


uci:save('fastd')
