/* SPDX-License-Identifier: ISC */
#include "servicecmd.h"
#include "initsock.h"
#include "service.h"
#include "config.h"

#include <fnmatch.h>
#include <getopt.h>
#include <unistd.h>

static const struct option long_opts[] = {
	{ "detail", no_argument, NULL, 'd' },
	{ NULL, 0, NULL, 0 },
};

static const char *short_opts = "d";

static void free_resp(init_status_response_t *resp)
{
	free(resp->filename);
	free(resp->service_name);
}

static int cmd_status(int argc, char **argv)
{
	bool is_tty, found, show_details = false;
	int i, fd, ret = EXIT_FAILURE;
	init_status_response_t resp;
	char tmppath[256];
	const char *state;

	for (;;) {
		i = getopt_long(argc, argv, short_opts, long_opts, NULL);
		if (i == -1)
			break;

		switch (i) {
		case 'd':
			show_details = true;
			break;
		default:
			tell_read_help(argv[0]);
			return EXIT_FAILURE;
		}
	}

	sprintf(tmppath, "/tmp/svcstatus.%d.sock", (int)getpid());
	fd = init_socket_open(tmppath);

	if (fd < 0) {
		unlink(tmppath);
		return EXIT_FAILURE;
	}

	if (init_socket_send_request(fd, EIR_STATUS))
		goto out;

	is_tty = (isatty(STDOUT_FILENO) == 1);

	for (;;) {
		memset(&resp, 0, sizeof(resp));

		if (init_socket_recv_status(fd, &resp)) {
			perror("reading from initd socket");
			free_resp(&resp);
			goto out;
		}

		if (resp.state == ESS_NONE) {
			free_resp(&resp);
			break;
		}

		if (optind < argc) {
			found = false;

			for (i = optind; i < argc; ++i) {
				if (fnmatch(argv[i], resp.filename, 0) == 0) {
					found = true;
					break;
				}
			}

			if (!found)
				continue;
		}

		switch (resp.state) {
		case ESS_RUNNING:
			if (!is_tty) {
				state = "UP";
				break;
			}
			state = "\033[22;32m UP \033[0m";
			break;
		case ESS_ENQUEUED:
			state = "SCHED";
			break;
		case ESS_FAILED:
			if (!is_tty) {
				state = "FAIL";
				break;
			}
			state = "\033[22;31mFAIL\033[0m";
			break;
		case ESS_DONE:
			if (!is_tty) {
				state = "DONE";
				break;
			}

			state = "\033[22;33mDONE\033[0m";
			break;
		default:
			if (!is_tty) {
				state = "UNKNOWN";
				break;
			}
			state = "\033[22;31mUNKNOWN\033[0m";
			break;
		}

		if (show_details) {
			printf("Service: %s\n", resp.filename);
			printf("\tStatus: %s\n", state);
			printf("\tTemplate name: %s\n", resp.service_name);
			printf("\tExit status: %d\n", resp.exit_status);
		} else {
			printf("[%s] %s\n", state, resp.filename);
		}

		free_resp(&resp);
	}

	ret = EXIT_SUCCESS;
out:
	close(fd);
	unlink(tmppath);
	return ret;
}

static command_t status = {
	.cmd = "status",
	.usage = "[-d|--detail] [services...]",
	.s_desc = "report the status of the currently enabled services",
	.l_desc = "Gathers a list of all currently running services and the "
		  "state that they are in (currently running, done, failed, "
		  "wating to get scheduled). A list of services with wildcard "
		  "globbing patterns can be specified. If ommitted, produces "
		  "a general overview of all services. If the --detail "
		  "is given, more details are shown about a service.",
	.run_cmd = cmd_status,
};

REGISTER_COMMAND(status)