/* Copyright (C) 2025 by sysmocom - s.f.m.c. GmbH <info@sysmocom.de>
 * Author: Vadim Yanitskiy <vyanitskiy@sysmocom.de>
 *
 * All Rights Reserved
 *
 * SPDX-License-Identifier: MPL-2.0
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0.  If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#include <stdlib.h>
#include <string.h>
#include <erl_nif.h>

#include <nftables/libnftables.h>

static int
load_cb(ErlNifEnv *env, void **priv, ERL_NIF_TERM load_info)
{
	struct nft_ctx *ctx;

	ctx = nft_ctx_new(NFT_CTX_DEFAULT);
	if (ctx == NULL)
		return -1;

	/* do not write directly to stdout/stderr */
	if (nft_ctx_buffer_output(ctx) != 0) {
		nft_ctx_free(ctx);
		return -2;
	}
	if (nft_ctx_buffer_error(ctx) != 0) {
		nft_ctx_free(ctx);
		return -3;
	}

	/* enable JSON output */
	nft_ctx_output_set_flags(ctx, NFT_CTX_OUTPUT_JSON);

	*priv = (void *)ctx;
	return 0;
}

static void
unload_cb(ErlNifEnv *env, void *priv)
{
	struct nft_ctx *ctx = (struct nft_ctx *)priv;

	nft_ctx_unbuffer_output(ctx);
	nft_ctx_free(ctx);
}

static ERL_NIF_TERM
run_cmd_nif(ErlNifEnv *env, int argc, const ERL_NIF_TERM argv[])
{
	struct nft_ctx *ctx;
	ErlNifBinary bin;
	int rc;

	ctx = (struct nft_ctx *)enif_priv_data(env);

	if (!enif_inspect_binary(env, argv[0], &bin))
		return enif_make_badarg(env);

	rc = nft_run_cmd_from_buffer(ctx, (const char *)bin.data);
	if (rc == 0) {
		const char *obuf = nft_ctx_get_output_buffer(ctx);
		bin.data = (unsigned char *)obuf;
		bin.size = strlen(obuf);
		return enif_make_tuple2(env,
					enif_make_atom(env, "ok"),
					enif_make_binary(env, &bin));
	} else {
		const char *ebuf = nft_ctx_get_error_buffer(ctx);
		return enif_make_tuple2(env,
					enif_make_atom(env, "error"),
					enif_make_string(env, ebuf, ERL_NIF_LATIN1));
	}

}

static ErlNifFunc nif_funcs[] = {
	{ "run_cmd_nif", 1, &run_cmd_nif },
};

ERL_NIF_INIT(enftables, nif_funcs, &load_cb, NULL, NULL, &unload_cb);
