/*
 * Purple - Internet Messaging Library
 * Copyright (C) Pidgin Developers <devel@pidgin.im>
 *
 * Purple is the legal property of its developers, whose names are too numerous
 * to list here.  Please refer to the COPYRIGHT file distributed with this
 * source distribution.
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, see <https://www.gnu.org/licenses/>.
 */

#include <glib.h>

#include <birb.h>

#include <purple.h>

/******************************************************************************
 * Globals
 *****************************************************************************/
#define TEST_PURPLE_PROTOCOL_DIRECTORY_DOMAIN (g_quark_from_static_string("test-protocol-contacts"))

/******************************************************************************
 * TestProtocolContacts implementation
 *****************************************************************************/
G_DECLARE_FINAL_TYPE(TestPurpleProtocolDirectory,
                     test_purple_protocol_directory, TEST_PURPLE,
                     PROTOCOL_DIRECTORY, PurpleProtocol)

struct _TestPurpleProtocolDirectory {
	PurpleProtocol parent;

	gboolean should_error;

	guint search_contacts_async;
	guint search_contacts_finish;
};

static void
test_purple_protocol_directory_search_contacts_async(PurpleProtocolDirectory *directory,
                                                    PurpleAccount *account,
                                                    const char *text,
                                                    GCancellable *cancellable,
                                                    GAsyncReadyCallback callback,
                                                    gpointer data)
{
	TestPurpleProtocolDirectory *protocol = NULL;
	GTask *task = NULL;

	birb_assert_type(account, PURPLE_TYPE_ACCOUNT);
	g_assert_false(birb_str_is_empty(text));

	protocol = TEST_PURPLE_PROTOCOL_DIRECTORY(directory);
	protocol->search_contacts_async += 1;

	task = g_task_new(directory, cancellable, callback, data);
	if(protocol->should_error) {
		GError *error = g_error_new_literal(TEST_PURPLE_PROTOCOL_DIRECTORY_DOMAIN,
		                                    0, "error");
		g_task_return_error(task, error);
	} else {
		g_task_return_pointer(task, purple_contacts_new(), g_object_unref);
	}

	g_clear_object(&task);
}

static PurpleContacts *
test_purple_protocol_directory_search_contacts_finish(PurpleProtocolDirectory *directory,
                                                     GAsyncResult *result,
                                                     GError **error)
{
	TestPurpleProtocolDirectory *protocol = NULL;

	protocol = TEST_PURPLE_PROTOCOL_DIRECTORY(directory);
	protocol->search_contacts_finish += 1;

	return g_task_propagate_pointer(G_TASK(result), error);
}

static void
test_purple_protocol_directory_iface_init(PurpleProtocolDirectoryInterface *iface)
{
	iface->search_contacts_async =
		test_purple_protocol_directory_search_contacts_async;
	iface->search_contacts_finish =
		test_purple_protocol_directory_search_contacts_finish;
}

G_DEFINE_FINAL_TYPE_WITH_CODE(TestPurpleProtocolDirectory,
                              test_purple_protocol_directory,
                              PURPLE_TYPE_PROTOCOL,
                              G_IMPLEMENT_INTERFACE(PURPLE_TYPE_PROTOCOL_DIRECTORY,
                                                    test_purple_protocol_directory_iface_init))

static void
test_purple_protocol_directory_init(TestPurpleProtocolDirectory *protocol) {
	protocol->search_contacts_async = 0;
	protocol->search_contacts_finish = 0;
}

static void
test_purple_protocol_directory_class_init(G_GNUC_UNUSED TestPurpleProtocolDirectoryClass *klass)
{
}

/******************************************************************************
 * TestProtocolDirectory search contacts tests
 *****************************************************************************/
static void
test_purple_protocol_directory_search_contacts_cb(GObject *obj,
                                                 GAsyncResult *res,
                                                 G_GNUC_UNUSED gpointer data)
{
	TestPurpleProtocolDirectory *protocol = NULL;
	PurpleContacts *result = NULL;
	PurpleProtocolDirectory *directory = NULL;
	GError *error = NULL;

	protocol = TEST_PURPLE_PROTOCOL_DIRECTORY(obj);
	directory = PURPLE_PROTOCOL_DIRECTORY(obj);

	result = purple_protocol_directory_search_contacts_finish(directory, res,
	                                                          &error);
	if(protocol->should_error) {
		g_assert_error(error, TEST_PURPLE_PROTOCOL_DIRECTORY_DOMAIN, 0);
		g_clear_error(&error);
		g_assert_null(result);
	} else {
		g_assert_no_error(error);
		birb_assert_type(result, PURPLE_TYPE_CONTACTS);
		g_clear_object(&result);
	}
}

static void
test_purple_protocol_directory_search_contacts_normal(void) {
	TestPurpleProtocolDirectory *protocol = NULL;
	PurpleAccount *account = NULL;

	protocol = g_object_new(test_purple_protocol_directory_get_type(), NULL);
	account = purple_account_new("test", "test");

	purple_protocol_directory_search_contacts_async(PURPLE_PROTOCOL_DIRECTORY(protocol),
	                                                account,
	                                                "bob",
	                                                NULL,
	                                                test_purple_protocol_directory_search_contacts_cb,
	                                                NULL);

	g_main_context_iteration(NULL, FALSE);

	g_assert_cmpuint(protocol->search_contacts_async, ==, 1);
	g_assert_cmpuint(protocol->search_contacts_finish, ==, 1);

	g_assert_finalize_object(protocol);
	g_assert_finalize_object(account);
}

static void
test_purple_protocol_directory_search_contacts_error(void) {
	TestPurpleProtocolDirectory *protocol = NULL;
	PurpleAccount *account = NULL;

	protocol = g_object_new(test_purple_protocol_directory_get_type(), NULL);
	protocol->should_error = TRUE;

	account = purple_account_new("test", "test");

	purple_protocol_directory_search_contacts_async(PURPLE_PROTOCOL_DIRECTORY(protocol),
	                                                account,
	                                                "bob",
	                                                NULL,
	                                                test_purple_protocol_directory_search_contacts_cb,
	                                                NULL);

	g_main_context_iteration(NULL, FALSE);

	g_assert_cmpuint(protocol->search_contacts_async, ==, 1);
	g_assert_cmpuint(protocol->search_contacts_finish, ==, 1);

	g_assert_finalize_object(protocol);
	g_assert_finalize_object(account);
}

/******************************************************************************
 * Main
 *****************************************************************************/
int
main(int argc, char **argv) {
	g_test_init(&argc, &argv, NULL);

	g_test_set_nonfatal_assertions();

	g_test_add_func("/protocol-contacts/normal/search-async-normal",
	                test_purple_protocol_directory_search_contacts_normal);
	g_test_add_func("/protocol-contacts/normal/search-async-error",
	                test_purple_protocol_directory_search_contacts_error);

	return g_test_run();
}
