/* SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only */
/* Copyright (c) 2025 Brett A C Sheffield <bacs@librecast.net> */

#include "test.h"
#include <agent.h>
#include <librecast/crypto.h>

#define REDIRECT_BUF f = freopen("/dev/null", "a", stderr); assert(f); setbuf(stderr, buf);
#define REDIRECT_OUT setbuf(stderr, NULL);
#define CHANNEL_NAME "0000-0017"

int verify_disk_token(state_t *state, char *fakehome, char *buf, uint64_t expires)
{
	unsigned char hash[HASHSIZE];
	lc_token_t token;
	int rc = state_dirs(state, fakehome);

	if (!test_assert(rc == 0, "%s() state_dirs", __func__)) return test_status;
	hash_generic(hash, sizeof hash, (unsigned char *)CHANNEL_NAME, strlen(CHANNEL_NAME));
	rc = key_cap_load(&token, state, hash, sizeof token.channel);
	perror("key_cap_load");
	test_assert(rc == 0, "key_cap_load()");

	/* while we're here, check cmd output contains token path */
	char *tokpath = key_cap_path(state, hash, sizeof token.channel);
	if (!test_assert(tokpath != NULL, "key_cap_path()")) return test_status;
	test_assert(strstr(buf, tokpath) != NULL, "token path printed");
	free(tokpath);

	test_assert(token.expires >= expires, "token expires");

	free_state(state);

	return rc;
}

int main(void)
{
	char name[] = PACKAGE_NAME " sign";
	char fakehome[] = "0000-0017-XXXXXX";
	char buf[BUFSIZ];
	state_t state = {0};
	FILE *f;
	int argc;
	int rc;

	test_name(name);

	/* create fake home directory */
	if (!test_assert(mkdtemp(fakehome) != NULL, "mkdtemp()")) {
		perror("mkdtemp");
		return test_status;
	}
	setenv("HOME", fakehome, 1);

	/* redirect agent output to buffer */
	memset(buf, 0, sizeof buf); /* clear output buffer */

	/* missing key argument => EINVAL */
	char *argv_nokey[] = { PACKAGE_NAME, "sign", NULL };
	argc = sizeof argv_nokey / sizeof argv_nokey[0] - 1;
	errno = 0;
	REDIRECT_BUF
	rc = agent(&state, argc, argv_nokey);
	REDIRECT_OUT
	test_assert(errno == EINVAL, "EINVAL");
	test_assert(rc == EXIT_FAILURE, "agent() returned %i", rc);
	/* verify cmd output (error message) */
	test_assert(strstr(buf, AGENT_ERR_NOKEY) != NULL, "error message found in output");

	/* missing chan argument => EINVAL */
	char *argv_nochan[] = { PACKAGE_NAME, "sign", "somekey", NULL };
	argc = sizeof argv_nochan / sizeof argv_nochan[0] - 1;
	memset(buf, 0, sizeof buf); /* clear output buffer */
	errno = 0;
	REDIRECT_BUF
	rc = agent(&state, argc, argv_nochan);
	REDIRECT_OUT
	test_assert(errno == EINVAL, "EINVAL");
	test_assert(rc == EXIT_FAILURE, "agent() returned %i", rc);
	/* verify cmd output (error message) */
	test_assert(strstr(buf, AGENT_ERR_NOCHANNEL) != NULL, "error message found in output");

	/* run once, issue token to disk */
	char bearerkey[] = "byteme";
	char *argv_ok[] = { PACKAGE_NAME, "sign", bearerkey, CHANNEL_NAME, NULL };
	argc = sizeof argv_ok / sizeof argv_ok[0] - 1;
	memset(buf, 0, sizeof buf); /* clear output buffer */
	memset(&state, 0, sizeof state);
	errno = 0;
	REDIRECT_BUF
	rc = agent(&state, argc, argv_ok);
	REDIRECT_OUT
	test_assert(rc == 0, "agent_run() returned %i", rc);

	/* verify token on disk */
	if (verify_disk_token(&state, fakehome, buf, 0)) return test_status;

	/* issue token with --expires option */
	char *argv_expires[] = { PACKAGE_NAME, "sign", "--expires", "60",
		bearerkey, CHANNEL_NAME, NULL };
	argc = sizeof argv_expires / sizeof argv_expires[0] - 1;
	memset(&state, 0, sizeof state);
	rc = agent(&state, argc, argv_expires);
	test_assert(rc == 0, "agent_run() returned %i", rc);
	test_assert(state.expires == 60, "state.expires set");

	/* check token has non-zero expiry */
	if (verify_disk_token(&state, fakehome, buf, 60)) return test_status;

	return test_status;
}
