/*
 * selftest.c: SelfTestDiagnostics datamodel handler
 *
 * Copyright (C) 2023-2024 IOPSYS Software Solutions AB. All rights reserved.
 *
 *
 * See LICENSE file for license related information.
 */

#include <sys/stat.h>

#include "libbbfdm-api/dmcommon.h"

#define DIAG_BIN "/usr/sbin/self-diagnostics"

static char *get_selftest_log_instance(struct dmctx *ctx)
{
	char *file_name = NULL;
	char *path = NULL;
	char *file_uri = NULL;

	struct uci_section *s = get_origin_section_from_dmmap("dmmap_logmngr", "self_test", "self_test_log");
	if (s == NULL)
		goto err;

	dmuci_get_value_by_section_string(s, "log_file", &file_name);
	if (DM_STRLEN(file_name) == 0)
		goto err;

	dmasprintf(&file_uri, "file://%s", file_name);
	_bbfdm_get_references(ctx, "Device.DeviceInfo.VendorLogFile.", "Name", file_uri, &path);

err:
	return path ? path : dmstrdup("");
}

/*************************************************************
* OPERATE COMMAND
**************************************************************/
static operation_args device_self_test_args = {
	.out = (const char *[]) {
		"Status",
		"Results",
		NULL
	}
};

int get_operate_args_SelfTest(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = (char *)&device_self_test_args;
	return 0;
}

int operate_Device_SelfTest(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	char cmd[512] = {0};
	char buffer[512] = {0};
	json_object *jobj = NULL;
	const char *filename;

	snprintf(cmd, sizeof(cmd), "sh %s -j 2>/dev/null", DIAG_BIN);

	if (run_cmd(cmd, buffer, sizeof(buffer)) != 0) {
		BBFDM_ERR("Failed to run cmd[%s]", cmd);
		goto err;
	}

	if (DM_STRLEN(buffer) == 0) {
		BBFDM_ERR("No output from cmd[%s]", cmd);
		goto err;
	}

	jobj = json_tokener_parse(buffer);
	if (jobj == NULL) {
		BBFDM_ERR("Fail to parse output[%s] in json", buffer);
		goto err;
	}

	filename = dmjson_get_value(jobj, 1, "result");
	snprintf(buffer, sizeof(buffer), "%s", filename);
	json_object_put(jobj);
	if (!file_exists(filename)) {
		BBFDM_ERR("File [%s] does not exists or not accessible", filename);
		goto err;
	}

	/* Add in dmmap_logmngr */
	struct uci_section *s = get_origin_section_from_dmmap("dmmap_logmngr", "self_test", "self_test_log");
	if (s == NULL) {
		dmuci_add_section_bbfdm("dmmap_logmngr", "self_test", &s);
		dmuci_rename_section_by_section(s, "self_test_log");
	}

	dmuci_set_value_by_section(s, "log_file", filename);
	dmuci_commit_package_bbfdm("dmmap_logmngr");

	/* Get self test log instance */
	char *result = get_selftest_log_instance(ctx);

	fill_blob_param(&ctx->bb, "Status", "Complete", DMT_TYPE[DMT_STRING], 0);
	fill_blob_param(&ctx->bb, "Results", result, DMT_TYPE[DMT_STRING], 0);

	if (ctx->dm_type != BBFDM_USP) {
		diagnostics_set_option("selftest", "DiagnosticState", "Complete");
		dmuci_commit_package_bbfdm(DMMAP_DIAGNOSTIGS);
	}

	return 0;

err:
	fill_blob_param(&ctx->bb, "Status", "Error_Internal", DMT_TYPE[DMT_STRING], 0);
	if (ctx->dm_type != BBFDM_USP) {
		diagnostics_set_option("selftest", "DiagnosticState", "Error");
		dmuci_commit_package_bbfdm(DMMAP_DIAGNOSTIGS);
	}

	return USP_FAULT_COMMAND_FAILURE;
}

/*************************************************************
* GET & SET PARAM
**************************************************************/
static int get_SelfTest_DiagnosticsState(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = diagnostics_get_option_fallback_def("selftest", "DiagnosticState", "None");
	return 0;
}

static int set_SelfTest_DiagnosticsState(char *refparam, struct dmctx *ctx, void *data, char *instance, char *value, int action)
{
	switch (action) {
		case VALUECHECK:
			if (bbfdm_validate_string(ctx, value, -1, -1, DiagnosticsState, NULL))
				return FAULT_9007;
			break;
		case VALUESET:
			if (DM_LSTRCMP(value, "Requested") == 0)
				diagnostics_set_option("selftest", "DiagnosticState", value);
	}
	return 0;
}

static int get_SelfTest_Results(char *refparam, struct dmctx *ctx, void *data, char *instance, char **value)
{
	*value = get_selftest_log_instance(ctx);
	return 0;
}

/**********************************************************************************************************************************
*                                            OBJ & LEAF DEFINITION
***********************************************************************************************************************************/
DMLEAF tSelfTestParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type*/
{"DiagnosticsState", &DMWRITE, DMT_STRING, get_SelfTest_DiagnosticsState, set_SelfTest_DiagnosticsState, BBFDM_CWMP},
{"Results", &DMREAD, DMT_STRING, get_SelfTest_Results, NULL, BBFDM_CWMP, DM_FLAG_REFERENCE},
{0}
};

DMOBJ tDeviceObjs[] = {
{"SelfTestDiagnostics", &DMREAD, NULL, NULL, NULL, NULL, NULL, NULL, NULL, tSelfTestParams, NULL, BBFDM_CWMP, NULL},
{0}
};

DMLEAF tDeviceParams[] = {
/* PARAM, permission, type, getvalue, setvalue, bbfdm_type, version*/
{"SelfTestDiagnostics()", &DMASYNC, DMT_COMMAND, get_operate_args_SelfTest, operate_Device_SelfTest, BBFDM_USP},
{0}
};

DM_MAP_OBJ tDynamicObj[] = {
/* parentobj, nextobject, parameter */
{"Device.", tDeviceObjs, tDeviceParams},
{0}
};
