#include <src/query/command2.h>
#include <codecvt>
#include <locale>
#include <string>
#include <cassert>
#include <src/misc/base64.h>
#include <sstream>
#include <src/License.h>
#include <functional>
#include "PermissionManager.h"

#include "src/query/command_constants.h"

using namespace std;
using namespace ts;
using namespace license::teamspeak;

template <class key_t, typename value_type_t>
using field = ts::descriptor::field<key_t, value_type_t>;

template <class key_t>
using trigger = ts::descriptor::trigger<key_t>;

void handleCommand(
		ts::command& _cmd,
		const cconstants::return_code::optional& return_code,
		const field<tl("key_a"), int>& key_a,
		const field<tl("key_b"), string>::optional& key_b,
		const field<tl("key_c"), uint64_t>::optional::bulked& key_c,
		const trigger<tl("test")>& switch_test
) {
	if(key_a.value() < 10)
		cout << "ERROR" << endl;
	auto b = key_c.as<string>();
	string key_c_str = key_c;

	auto c = key_b.has_value();

	cout << key_c[1].value() << endl;
	cout << "Return code: " << return_code.get_or<string>("XXX") << endl;
	__asm__("nop");
}

command_result test() {
	return command_result{error::vs_critical};
}

command_result test2() {
	return command_result{permission::b_virtualserver_select_godmode};
}

command_result test3() {
	return command_result{error::vs_critical, "unknown error"};
}

void eval_test(command_result x) {
	if(x.is_detailed()) {
		cout << "Detailed!" << endl;
		delete x.release_details();
	} else {
		auto a = x.permission_id();
		auto b = x.error_code();
		cout << (void*) a << " - " << (void*) b << endl;
	}
}

int main() {
	//for(const auto& error : avariableErrors)
	//	cout << error.name << " = " << hex << "0x" << error.errorId << "," << endl;

	eval_test(test());
	eval_test(test2());
	eval_test(test3());
	/*
	ios_base::sync_with_stdio(false); // Avoids synchronization with C stdio on gcc
	// (either localize both or disable sync)

	wcout.imbue(locale("de_DE.ISO-8859-1")); // change default locale

	//░█▀▀▀█░░░░▄█░░░░░░░░░▄█░░░░░▄█░░
	const auto message = "\221\210\200\200\200\210\221\221\221\221\204\210\221\221\221\221\221\221\221\221\221\204\210\221\221\221\221\221\204\210\221\221";
	const auto auto_message = "░█▀▀▀█░░░░▄█░░░░░░░░░▄█░░░░░▄█░░";
	cout << " -> " << message << endl;
	cout << " -> " << utf8_check_is_valid(message) << endl;
	cout << " -> " << utf8_check_is_valid("░█▀▀▀█░░░░▄█░░░░░░░░░▄█░░░░░▄█░░") << endl;

    Command cmd = Command::parse("test -mapping test=░█▀▀▀█░░░░▄█░░░░░░░░░▄█░░░░░▄█░░_ -x");
    cout << "Build: " << cmd.build() << endl;
    cout << "X: " << cmd["test"] << endl;
	cout << " -> " << endl;
	for(const auto& e : cmd.parms())
		cout << e << endl;
	 */

	/*
	auto handle = make_shared<ts::impl::command_value>();

	ts::command_entry entry(handle);
	entry = 255;
	cout << "Value: " << entry.as<int>() << endl;
	cout << "Value: " << entry.melt().as<uint32_t>() << endl;

	cout << "Str: " << entry.string() << endl;
	cout << "U8: " << (int) entry.melt().as<uint8_t>() << endl;
	 */

	//register_function(handleCommand);

	cout << sizeof(command_result) << endl;
	ts::command cmd("notify");

	cout << ts::command::parse("test a=b ").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
	cout << ts::command::parse("test a=").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
	cout << ts::command::parse("test a").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
	cout << ts::command::parse("a=c", false).build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
	cout << ts::command::parse("a=c | a=c -x", false).build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
	cout << ts::command::parse("a a=c|a=c").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;
	cout << ts::command::parse("a a=c a=c2 -z | -?  a=c").build(ts::command::format::BRACE_ESCAPED_QUERY) << endl;

	/*
	 *
	cmd[0]["key_a"] = 2;
	cmd["b"] = 3;
	cmd["c"] = "Hello World";
	cmd["c"] = "Hello World" + string();
	cmd["c"] = 2;
	cmd.set_trigger("test");
	cmd.set_trigger("test2");
	cout << "Key_A => " << cmd[0]["key_a"].string() << endl;
	 */
	cmd["key_a"] = "0";
	cmd["key_b"] = "key_b_value";
	cmd["return_code"] = "ASD";
	cmd[0]["key_c"] = "key_c_value_0";
	cmd[1]["key_c"] = "key_c_value_1";
	cmd.set_trigger("test");

	auto result = ts::descriptor::describe_function(handleCommand);

	auto cmd_handler = ts::descriptor::parse_function(handleCommand);
	cmd_handler->invoke(cmd);
	cout << cmd.build() << endl;

	//auto v = ts::descriptor::entry::bulked::val;
    return 0;
}