/*
 * Copyright Nico Sonack <nsonack@herrhotzenplotz.de>
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 * copyright notice, this list of conditions and the following
 * disclaimer in the documentation and/or other materials provided
 * with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <gcli/cmd/cmd.h>
#include <gcli/cmd/comment.h>
#include <gcli/cmd/interactive.h>
#include <gcli/cmd/issues.h>
#include <gcli/cmd/pulls.h>
#include <gcli/cmd/status_interactive.h>
#include <gcli/cmd/table.h>

#include <gcli/status.h>

#include <string.h>

static void
print_notification_table(struct gcli_notification_list const *list)
{
	gcli_tbl *table;
	struct gcli_tblcoldef columns[] = {
		{ .name = "NUMBER", .type = GCLI_TBLCOLTYPE_LONG,   .flags = 0 },
		{ .name = "REPO",   .type = GCLI_TBLCOLTYPE_STRING, .flags = 0 },
		{ .name = "TYPE",   .type = GCLI_TBLCOLTYPE_STRING, .flags = 0 },
		{ .name = "REASON", .type = GCLI_TBLCOLTYPE_STRING, .flags = 0 },
	};

	table = gcli_tbl_begin(columns, ARRAY_SIZE(columns));

	for (size_t i = 0; i < list->notifications_size; ++i) {
		struct gcli_notification const *n = &list->notifications[i];
		gcli_tbl_add_row(table, (long)i + 1, n->repository,
		                 gcli_notification_target_type_str(n->type),
		                 n->reason);
	}

	gcli_tbl_end(table);
}

static void
refresh_notifications(struct gcli_notification_list *list)
{
	int rc = 0;

	gcli_free_notifications(list);

	rc = gcli_get_notifications(g_clictx, -1, list);
	if (rc < 0)
		errx(1, "gcli: failed to fetch notifications: %s", gcli_get_error(g_clictx));
}

static struct gcli_cmd_actions *
notification_handlers[MAX_GCLI_NOTIFICATION_TARGET] = {
	[GCLI_NOTIFICATION_TARGET_ISSUE] = &gcli_issue_actions,
	[GCLI_NOTIFICATION_TARGET_PULL_REQUEST] = &gcli_pull_actions,
};

static void
status_interactive_notification(struct gcli_notification const *const notif)
{
	char *user_input = NULL;

	if (notif->type >= MAX_GCLI_NOTIFICATION_TARGET) {
		fprintf(stderr, "gcli: error: bad notification type\n");
		return;
	}

	if (notification_handlers[notif->type] == NULL) {
		fprintf(stderr, "gcli: error: notification type '%s' not supported\n",
		        gcli_notification_target_type_str(notif->type));
		return;
	}

	struct gcli_cmd_actions const *const actions =
		notification_handlers[notif->type];

	for (;;) {
		int rc = 0;

		user_input = gcli_cmd_prompt("Enter action, done or quit", GCLI_PROMPT_RESULT_MANDATORY);

		/* plain quit action */
		if (strcmp(user_input, "q") == 0 ||
		    strcmp(user_input, "quit") == 0) {
			free(user_input);
			return;
		}

		/* mark as done and quit */
		if (strcmp(user_input, "d") == 0 ||
		    strcmp(user_input, "done") == 0) {
			rc = gcli_notification_mark_as_read(g_clictx, notif->id);
			if (rc < 0)
				fprintf(stderr, "gcli: error: %s\n", gcli_get_error(g_clictx));

			free(user_input);
			return;
		}

		/* search and call action handler or error out */
		rc = gcli_cmd_action_handle(actions, &notif->target, user_input);
		if (rc < 0) {
			fprintf(stderr, "gcli: error: %s\n", gcli_get_error(g_clictx));
		}

		free(user_input);
	}
}

int
gcli_status_interactive(void)
{
	struct gcli_notification_list list = {0};
	char *user_input = NULL;

	refresh_notifications(&list);
	print_notification_table(&list);

	for (;;) {
		user_input = gcli_cmd_prompt("Enter number, list or quit", GCLI_PROMPT_RESULT_MANDATORY);

		if (strcmp(user_input, "q") == 0 ||
		    strcmp(user_input, "quit") == 0) {
			goto out;

		} else if (strcmp(user_input, "l") == 0 ||
		           strcmp(user_input, "list") == 0) {
			refresh_notifications(&list);
			print_notification_table(&list);

		} else {
			size_t number = 0;
			char *endptr = NULL;

			number = strtoul(user_input, &endptr, 10);
			if (endptr != user_input + strlen(user_input)) {
				fprintf(stderr, "gcli: bad notification number: %s\n",
				        user_input);

				goto next;
			}

			if (number == 0 || number > list.notifications_size) {
				fprintf(stderr, "gcli: unknown notification number\n");
				goto next;
			}

			status_interactive_notification(&list.notifications[number-1]);
		}

	next:
		free(user_input);
		user_input = NULL;
	}

out:
	free(user_input);
	user_input = NULL;

	gcli_free_notifications(&list);

	return 0;
}
