#include <stdlib.h>
#include <string.h>

#include <json_object.h>
#include <linkhash.h>
#include <vali.h>

#include "ipc-gen.h"

#if __STDC_VERSION__ >= 202311L
#define MAYBE_UNUSED [[maybe_unused]]
#elif defined(__GNUC__)
#define MAYBE_UNUSED __attribute__((__unused__))
#else
#define MAYBE_UNUSED
#endif

#define HIDDEN
#if defined(__has_attribute)
#if __has_attribute(visibility)
#undef HIDDEN
#define HIDDEN __attribute__((visibility("hidden")))
#endif
#endif

MAYBE_UNUSED
static struct json_object *Reload_in_encode(const struct ipc_Reload_in *v) {
	struct json_object *raw = json_object_new_object();
	return raw;
}

MAYBE_UNUSED
static bool Reload_in_decode(struct ipc_Reload_in *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}


	return true;
}

MAYBE_UNUSED
static void ipc_Reload_in_finish(struct ipc_Reload_in *v) {
}

MAYBE_UNUSED
static struct json_object *Reload_out_encode(const struct ipc_Reload_out *v) {
	struct json_object *raw = json_object_new_object();
	return raw;
}

MAYBE_UNUSED
static bool Reload_out_decode(struct ipc_Reload_out *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}


	return true;
}

HIDDEN
void ipc_Reload_out_finish(struct ipc_Reload_out *v) {
}

HIDDEN
bool ipc_Reload(struct vali_client *c, const struct ipc_Reload_in *in, struct ipc_Reload_out *out, struct vali_error *err) {
	struct json_object *raw_in = Reload_in_encode(in);
	struct json_object *raw_out = NULL;
	if (!vali_client_call(c, "fr.emersion.kanshi.Reload", raw_in, &raw_out, err)) {
		return false;
	}
	bool ok = true;
	if (out != NULL) {
		*out = (struct ipc_Reload_out){0};
		ok = Reload_out_decode(out, raw_out);
	}
	json_object_put(raw_out);
	return ok;
}

HIDDEN
struct ipc_Reload_client_call ipc_Reload_more(struct vali_client *c, const struct ipc_Reload_in *in) {
	struct json_object *raw_in = Reload_in_encode(in);
	struct vali_client_call *call = vali_client_call_more(c, "fr.emersion.kanshi.Reload", raw_in);
	return (struct ipc_Reload_client_call){ .base = call };
}

HIDDEN
bool ipc_Reload_oneway(struct vali_client *c, const struct ipc_Reload_in *in) {
	struct json_object *raw_in = Reload_in_encode(in);
	return vali_client_call_oneway(c, "fr.emersion.kanshi.Reload", raw_in);
}

HIDDEN
bool ipc_Reload_client_call_wait(struct ipc_Reload_client_call call, struct ipc_Reload_out *out, struct vali_error *err) {
	struct json_object *raw_out = NULL;
	if (!vali_client_call_wait(call.base, &raw_out, err)) {
		return false;
	}
	bool ok = true;
	if (out != NULL) {
		*out = (struct ipc_Reload_out){0};
		ok = Reload_out_decode(out, raw_out);
	}
	json_object_put(raw_out);
	return ok;
}
HIDDEN
void ipc_Reload_close_with_reply(struct ipc_Reload_service_call call, const struct ipc_Reload_out *params) {
	struct json_object *raw = Reload_out_encode(params);
	vali_service_call_close_with_reply(call.base, raw);
}
HIDDEN
void ipc_Reload_reply(struct ipc_Reload_service_call call, const struct ipc_Reload_out *params) {
	struct json_object *raw = Reload_out_encode(params);
	vali_service_call_reply(call.base, raw);
}

MAYBE_UNUSED
static struct json_object *Switch_in_encode(const struct ipc_Switch_in *v) {
	struct json_object *raw = json_object_new_object();
	struct json_object *raw_profile = json_object_new_string(v->profile);
	json_object_object_add(raw, "profile", raw_profile);
	return raw;
}

MAYBE_UNUSED
static bool Switch_in_decode(struct ipc_Switch_in *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}

	struct json_object *raw_profile = json_object_object_get(obj, "profile");
	if (raw_profile == NULL) {
		return false;
	}
	if (json_object_get_type(raw_profile) != json_type_string) {
		return false;
	}
	out->profile = strdup(json_object_get_string(raw_profile));

	return true;
}

MAYBE_UNUSED
static void ipc_Switch_in_finish(struct ipc_Switch_in *v) {
	free(v->profile);
}

MAYBE_UNUSED
static struct json_object *Switch_out_encode(const struct ipc_Switch_out *v) {
	struct json_object *raw = json_object_new_object();
	return raw;
}

MAYBE_UNUSED
static bool Switch_out_decode(struct ipc_Switch_out *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}


	return true;
}

HIDDEN
void ipc_Switch_out_finish(struct ipc_Switch_out *v) {
}

HIDDEN
bool ipc_Switch(struct vali_client *c, const struct ipc_Switch_in *in, struct ipc_Switch_out *out, struct vali_error *err) {
	struct json_object *raw_in = Switch_in_encode(in);
	struct json_object *raw_out = NULL;
	if (!vali_client_call(c, "fr.emersion.kanshi.Switch", raw_in, &raw_out, err)) {
		return false;
	}
	bool ok = true;
	if (out != NULL) {
		*out = (struct ipc_Switch_out){0};
		ok = Switch_out_decode(out, raw_out);
	}
	json_object_put(raw_out);
	return ok;
}

HIDDEN
struct ipc_Switch_client_call ipc_Switch_more(struct vali_client *c, const struct ipc_Switch_in *in) {
	struct json_object *raw_in = Switch_in_encode(in);
	struct vali_client_call *call = vali_client_call_more(c, "fr.emersion.kanshi.Switch", raw_in);
	return (struct ipc_Switch_client_call){ .base = call };
}

HIDDEN
bool ipc_Switch_oneway(struct vali_client *c, const struct ipc_Switch_in *in) {
	struct json_object *raw_in = Switch_in_encode(in);
	return vali_client_call_oneway(c, "fr.emersion.kanshi.Switch", raw_in);
}

HIDDEN
bool ipc_Switch_client_call_wait(struct ipc_Switch_client_call call, struct ipc_Switch_out *out, struct vali_error *err) {
	struct json_object *raw_out = NULL;
	if (!vali_client_call_wait(call.base, &raw_out, err)) {
		return false;
	}
	bool ok = true;
	if (out != NULL) {
		*out = (struct ipc_Switch_out){0};
		ok = Switch_out_decode(out, raw_out);
	}
	json_object_put(raw_out);
	return ok;
}
HIDDEN
void ipc_Switch_close_with_reply(struct ipc_Switch_service_call call, const struct ipc_Switch_out *params) {
	struct json_object *raw = Switch_out_encode(params);
	vali_service_call_close_with_reply(call.base, raw);
}
HIDDEN
void ipc_Switch_reply(struct ipc_Switch_service_call call, const struct ipc_Switch_out *params) {
	struct json_object *raw = Switch_out_encode(params);
	vali_service_call_reply(call.base, raw);
}

MAYBE_UNUSED
static struct json_object *Status_in_encode(const struct ipc_Status_in *v) {
	struct json_object *raw = json_object_new_object();
	return raw;
}

MAYBE_UNUSED
static bool Status_in_decode(struct ipc_Status_in *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}


	return true;
}

MAYBE_UNUSED
static void ipc_Status_in_finish(struct ipc_Status_in *v) {
}

MAYBE_UNUSED
static struct json_object *Status_out_encode(const struct ipc_Status_out *v) {
	struct json_object *raw = json_object_new_object();
	struct json_object *raw_current_profile = NULL;
	if (v->current_profile != NULL) {
		raw_current_profile = json_object_new_string(v->current_profile);
	}
	json_object_object_add(raw, "current_profile", raw_current_profile);
	struct json_object *raw_pending_profile = NULL;
	if (v->pending_profile != NULL) {
		raw_pending_profile = json_object_new_string(v->pending_profile);
	}
	json_object_object_add(raw, "pending_profile", raw_pending_profile);
	return raw;
}

MAYBE_UNUSED
static bool Status_out_decode(struct ipc_Status_out *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}

	struct json_object *raw_current_profile = json_object_object_get(obj, "current_profile");
	if (raw_current_profile != NULL) {
		if (json_object_get_type(raw_current_profile) != json_type_string) {
			return false;
		}
		out->current_profile = strdup(json_object_get_string(raw_current_profile));
	}

	struct json_object *raw_pending_profile = json_object_object_get(obj, "pending_profile");
	if (raw_pending_profile != NULL) {
		if (json_object_get_type(raw_pending_profile) != json_type_string) {
			return false;
		}
		out->pending_profile = strdup(json_object_get_string(raw_pending_profile));
	}

	return true;
}

HIDDEN
void ipc_Status_out_finish(struct ipc_Status_out *v) {
	if (v->current_profile != NULL) {
		free(v->current_profile);
	}
	if (v->pending_profile != NULL) {
		free(v->pending_profile);
	}
}

HIDDEN
bool ipc_Status(struct vali_client *c, const struct ipc_Status_in *in, struct ipc_Status_out *out, struct vali_error *err) {
	struct json_object *raw_in = Status_in_encode(in);
	struct json_object *raw_out = NULL;
	if (!vali_client_call(c, "fr.emersion.kanshi.Status", raw_in, &raw_out, err)) {
		return false;
	}
	bool ok = true;
	if (out != NULL) {
		*out = (struct ipc_Status_out){0};
		ok = Status_out_decode(out, raw_out);
	}
	json_object_put(raw_out);
	return ok;
}

HIDDEN
struct ipc_Status_client_call ipc_Status_more(struct vali_client *c, const struct ipc_Status_in *in) {
	struct json_object *raw_in = Status_in_encode(in);
	struct vali_client_call *call = vali_client_call_more(c, "fr.emersion.kanshi.Status", raw_in);
	return (struct ipc_Status_client_call){ .base = call };
}

HIDDEN
bool ipc_Status_oneway(struct vali_client *c, const struct ipc_Status_in *in) {
	struct json_object *raw_in = Status_in_encode(in);
	return vali_client_call_oneway(c, "fr.emersion.kanshi.Status", raw_in);
}

HIDDEN
bool ipc_Status_client_call_wait(struct ipc_Status_client_call call, struct ipc_Status_out *out, struct vali_error *err) {
	struct json_object *raw_out = NULL;
	if (!vali_client_call_wait(call.base, &raw_out, err)) {
		return false;
	}
	bool ok = true;
	if (out != NULL) {
		*out = (struct ipc_Status_out){0};
		ok = Status_out_decode(out, raw_out);
	}
	json_object_put(raw_out);
	return ok;
}
HIDDEN
void ipc_Status_close_with_reply(struct ipc_Status_service_call call, const struct ipc_Status_out *params) {
	struct json_object *raw = Status_out_encode(params);
	vali_service_call_close_with_reply(call.base, raw);
}
HIDDEN
void ipc_Status_reply(struct ipc_Status_service_call call, const struct ipc_Status_out *params) {
	struct json_object *raw = Status_out_encode(params);
	vali_service_call_reply(call.base, raw);
}

MAYBE_UNUSED
static struct json_object *error_ProfileNotFound_encode(const struct ipc_error_ProfileNotFound *v) {
	struct json_object *raw = json_object_new_object();
	return raw;
}
MAYBE_UNUSED
static bool error_ProfileNotFound_decode(struct ipc_error_ProfileNotFound *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}


	return true;
}
bool ipc_error_ProfileNotFound_from(struct ipc_error_ProfileNotFound *out, const struct vali_error *err) {
	if (err->name == NULL || strcmp(err->name, "fr.emersion.kanshi.ProfileNotFound") != 0) {
		return false;
	}
	return error_ProfileNotFound_decode(out, err->parameters);
}
void ipc_error_ProfileNotFound_close_service_call(struct vali_service_call *call, const struct ipc_error_ProfileNotFound *params) {
	struct json_object *obj = error_ProfileNotFound_encode(params);
	vali_service_call_close_with_error(call, "fr.emersion.kanshi.ProfileNotFound", obj);
}

MAYBE_UNUSED
static struct json_object *error_ProfileNotMatched_encode(const struct ipc_error_ProfileNotMatched *v) {
	struct json_object *raw = json_object_new_object();
	return raw;
}
MAYBE_UNUSED
static bool error_ProfileNotMatched_decode(struct ipc_error_ProfileNotMatched *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}


	return true;
}
bool ipc_error_ProfileNotMatched_from(struct ipc_error_ProfileNotMatched *out, const struct vali_error *err) {
	if (err->name == NULL || strcmp(err->name, "fr.emersion.kanshi.ProfileNotMatched") != 0) {
		return false;
	}
	return error_ProfileNotMatched_decode(out, err->parameters);
}
void ipc_error_ProfileNotMatched_close_service_call(struct vali_service_call *call, const struct ipc_error_ProfileNotMatched *params) {
	struct json_object *obj = error_ProfileNotMatched_encode(params);
	vali_service_call_close_with_error(call, "fr.emersion.kanshi.ProfileNotMatched", obj);
}

MAYBE_UNUSED
static struct json_object *error_ProfileNotApplied_encode(const struct ipc_error_ProfileNotApplied *v) {
	struct json_object *raw = json_object_new_object();
	return raw;
}
MAYBE_UNUSED
static bool error_ProfileNotApplied_decode(struct ipc_error_ProfileNotApplied *out, struct json_object *obj) {
	if (json_object_get_type(obj) != json_type_object && obj != NULL) {
		return false;
	}


	return true;
}
bool ipc_error_ProfileNotApplied_from(struct ipc_error_ProfileNotApplied *out, const struct vali_error *err) {
	if (err->name == NULL || strcmp(err->name, "fr.emersion.kanshi.ProfileNotApplied") != 0) {
		return false;
	}
	return error_ProfileNotApplied_decode(out, err->parameters);
}
void ipc_error_ProfileNotApplied_close_service_call(struct vali_service_call *call, const struct ipc_error_ProfileNotApplied *params) {
	struct json_object *obj = error_ProfileNotApplied_encode(params);
	vali_service_call_close_with_error(call, "fr.emersion.kanshi.ProfileNotApplied", obj);
}

MAYBE_UNUSED
static void fail_method_not_implemented(struct vali_service_call *call, const char *method) {
	struct json_object *params = json_object_new_object();
	json_object_object_add(params, "method", json_object_new_string(method));
	vali_service_call_close_with_error(call, "org.varlink.service.MethodNotImplemented", params);
}

MAYBE_UNUSED
static void fail_invalid_parameter(struct vali_service_call *call, const char *param) {
	struct json_object *params = json_object_new_object();
	json_object_object_add(params, "parameter", json_object_new_string(param));
	vali_service_call_close_with_error(call, "org.varlink.service.InvalidParameter", params);
}

static void handle_call(struct vali_service_call *call, void *user_data) {
	const struct ipc_handler *handler = user_data;
	const char *method = vali_service_call_get_method(call);
	struct json_object *raw_in = vali_service_call_get_parameters(call);
	if (strcmp(method, "fr.emersion.kanshi.Reload") == 0) {
		if (handler->Reload == NULL) {
			fail_method_not_implemented(call, method);
			return;
		}
		struct ipc_Reload_in in = {0};
		if (!Reload_in_decode(&in, raw_in)) {
			fail_invalid_parameter(call, NULL);
			return;
		}
		handler->Reload((struct ipc_Reload_service_call){call}, &in);
		ipc_Reload_in_finish(&in);
		return;
	}
	if (strcmp(method, "fr.emersion.kanshi.Switch") == 0) {
		if (handler->Switch == NULL) {
			fail_method_not_implemented(call, method);
			return;
		}
		struct ipc_Switch_in in = {0};
		if (!Switch_in_decode(&in, raw_in)) {
			fail_invalid_parameter(call, NULL);
			return;
		}
		handler->Switch((struct ipc_Switch_service_call){call}, &in);
		ipc_Switch_in_finish(&in);
		return;
	}
	if (strcmp(method, "fr.emersion.kanshi.Status") == 0) {
		if (handler->Status == NULL) {
			fail_method_not_implemented(call, method);
			return;
		}
		struct ipc_Status_in in = {0};
		if (!Status_in_decode(&in, raw_in)) {
			fail_invalid_parameter(call, NULL);
			return;
		}
		handler->Status((struct ipc_Status_service_call){call}, &in);
		ipc_Status_in_finish(&in);
		return;
	}
	struct json_object *params = json_object_new_object();
	json_object_object_add(params, "method", json_object_new_string(method));
	vali_service_call_close_with_error(call, "org.varlink.service.MethodNotFound", params);
}

HIDDEN
const struct vali_registry_interface ipc_interface = {
	.name = "fr.emersion.kanshi",
	.definition =
		"interface fr.emersion.kanshi\n"
		"\n"
		"method Reload() -> ()\n"
		"method Switch(profile: string) -> ()\n"
		"method Status() -> (current_profile: ?string, pending_profile: ?string)\n"
		"\n"
		"error ProfileNotFound()\n"
		"error ProfileNotMatched()\n"
		"error ProfileNotApplied()\n"
		"",
};

HIDDEN
struct vali_service_call_handler ipc_get_call_handler(const struct ipc_handler *handler) {
	return (struct vali_service_call_handler){
		.func = handle_call,
		.user_data = (void *)handler,
	};
}

