/* 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 <log.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <unistd.h>

#define TEST_FMT_00 ""
#define TEST_FMT_01 "All human beings are born free and equal in dignity and rights\n"
#define TEST_FMT_02 "Everyone has the right to %s, %s and %s\n"
#define TEST_ARG_02 "life", "liberty", "security of person"
#define TEST_OUT_02 "Everyone has the right to life, liberty and security of person"

static int create_fakehome(char *fakehome)
{
	int rc;
	/* create fake home directory */
	if (!test_assert(mkdtemp(fakehome) != NULL, "mkdtemp()")) {
		perror("mkdtemp");
		return test_status;
	}
	rc = setenv("HOME", fakehome, 1);
	test_assert(rc == 0, "set HOME to %s", fakehome);
	return test_status;
}

static int test_logging_00(void)
{
	char fakehome[] = "0000-0027-XXXXXX";
	char configfile[] = "0000-0027-config.00.conf";
	state_t state = {0};
	int rc;

	if (create_fakehome(fakehome)) return test_status;
	rc = state_parse_configfile(&state, configfile);
	if (!test_assert(rc == 0, "state_parse_config(), rc = %i", rc)) return test_status;
	if (!test_assert(state.logfile != NULL, "state.logfile: %s", state.logfile)) goto err_free_state;

	/* chdir to fakehome to write logfile with relative path */
	rc = chdir(fakehome);
	if (!test_assert(rc == 0, "chdir() to %s", fakehome)) return test_status;

	rc = log_open(&state, NULL);
	if (!test_assert(rc == 0, "log_open() returned %i", rc)) return test_status;
	if (!test_assert(state.log != NULL, "state.log is not NULL")) goto err_free_state;

	rc = log_write(&state, TEST_FMT_00);
	if (!test_assert(rc == 0, "log_write() returned %i", rc)) goto err_free_state;

	rc = log_write(&state, TEST_FMT_01);
	if (!test_assert(rc == 0, "log_write() returned %i", rc)) goto err_free_state;

	rc = log_write(&state, TEST_FMT_02, TEST_ARG_02);
	if (!test_assert(rc == 0, "log_write() returned %i", rc)) goto err_free_state;

	rc = log_close(&state);
	if (!test_assert(rc == 0, "log_close() returned %i", rc)) goto err_free_state;
	if (!test_assert(state.log == NULL, "state.log is NULL")) goto err_free_state;

	/* check logfile exists */
	struct stat sb;
	rc = stat(state.logfile, &sb);
	test_assert(rc == 0, "stat %s", state.logfile);
	if (!test_assert(sb.st_size > 0, "%s size = %zu", state.logfile, sb.st_size)) goto err_free_state;

	/* verify log entries */
	char *buf;
	ssize_t byt;
	ssize_t byt_read = 0;
	int fd;
	buf = malloc(sb.st_size);
	if (!test_assert(buf != NULL, "malloc'ed buffer of %zu bytes", sb.st_size)) goto err_free_state;
	memset(buf, 0, sb.st_size);
	fd = open(state.logfile, O_RDONLY);
	if (!test_assert(fd != -1, "opened %s", state.logfile)) goto free_buf;
	for (char *ptr = buf; byt_read < sb.st_size; ptr += byt) {
		byt = read(fd, ptr, sb.st_size - byt_read);
		if (byt == -1) {
			perror("read");
			break;
		}
		if (byt > 0) byt_read += byt;
	}
	if (!test_assert(byt_read == sb.st_size, "read %zi bytes", byt_read)) goto close_fd;
	test_assert(strstr(buf, TEST_FMT_01) != NULL, "found '%s'", TEST_FMT_01);
	test_assert(strstr(buf, TEST_OUT_02) != NULL, "found '%s'", TEST_OUT_02);
close_fd:
	close(fd);
free_buf:
	free(buf);
err_free_state:
	free_state(&state);
	return test_status;
}

int main(void)
{
	char name[] = "logfile";

	test_name(name);

	if (test_logging_00()) return test_status;

	return test_status;
}
