#!/bin/sh

. /usr/share/libubox/jshn.sh
. /lib/functions.sh

HOST_LIST=""
PIDPATH="/etc/inadyn_pid"

get_service_state() {
	client_sec="${1}"

	service_name=$(uci -q get ddnsmngr.${client_sec}.service_name)
	if [ -z "${service_name}" ]; then
		echo "0"
		return
	fi

	service_sec=$(uci -q show ddnsmngr | grep "service=\'${service_name}\'" | cut -d'.' -f 2 | head -1)
	if [ -z "${service_sec}" ]; then
		echo "0"
		return
	fi

	enabled=$(uci -q get ddnsmngr.${service_sec}.enabled)

	echo "${enabled}"
	return
}

get_hostname_status() {
	host_section="${1}"

	enabled=$(uci -q get ddnsmngr.${host_section}.enabled)
	if [ -z "${enabled}" ] || [ "${enabled}" = "0" ]; then
		state="Disabled"
	else
		# Check client is enabled or not
		client_sec=$(uci -q get ddnsmngr.${host_section}.dm_parent)
		if [ -z "${client_sec}" ]; then
			echo "Error"
			return
		fi

		client_enabled=$(uci -q get ddnsmngr.${client_sec}.enabled)
		if [ -z "${client_enabled}" ] || [ "${client_enabled}" = "0" ]; then
			echo "Disabled"
			return
		fi

		service_enabled=$(get_service_state ${client_sec})
		if [ "${service_enabled}" = "0" ]; then
			echo "Disabled"
			return
		fi

		pid_file="${PIDPATH}/${host_section}"
		if [ ! -f "${pid_file}" ]; then
			state="Error"
		else
			pid=$(cat "${pid_file}")

			# collect log
			log_file="/tmp/log_inadyn_${pid}"
			logread -f -p /tmp/log_pid | grep "inadyn\[${pid}\]" > ${log_file} &

			# send SIGUSR2 to get current log
			kill -12 "${pid}"
			usleep 10000

			# stop logread and grep
			log_pid=$(cat /tmp/log_pid)
			if [ -n "${log_pid}" ]; then
				kill -9 "${log_pid}"
			fi

			if [ -f "${log_file}" ]; then
				state="Registered"
				while read -r line; do
					if [[ "${line}" =~ "Successful alias table update" ]] || [[ "${line}" =~ "Updating cache" ]]; then
						state="Registered"
					elif [[ "${line}" =~ "Fatal error" ]] || [[ "${line}" =~ "Error response from DDNS server" ]]; then
						state="Error"
					elif [[ "${line}" =~ "Failed Login" ]]; then
						state="Error_auth"
					elif [[ "${line}" =~ "Failed resolving hostname" ]]; then
						state="Error_dns"
					elif [[ "${line}" =~ "Invalid password" ]]; then
						state="Error_auth"
					fi
				done < "${log_file}"

				rm -rf "${log_file}"
			else
				state="Error"
			fi
		fi
	fi

	echo "${state}"
}

select_host() {
	host_sec="${1}"
	client_sec="${2}"

	config_get client_section "${host_sec}" dm_parent ""
	if [ "${client_sec}" != "${client_section}" ]; then
		return
	fi

	config_get_bool enabled "${host_sec}" enabled 0
	if [ "${enabled}" -eq 0 ]; then
		return
	fi

	HOST_LIST="${HOST_LIST} ${host_sec}"
}

get_enabled_hostnames() {
	client_section="${1}"
	HOST_LIST=""

	config_load ddnsmngr
	config_foreach select_host host ${1}

	echo "${HOST_LIST}"
}

get_client_status() {
	client_section="${1}"

	enabled=$(uci -q get ddnsmngr.${client_section}.enabled)
	if [ -z "${enabled}" ] || [ "${enabled}" = "0" ]; then
		state="Disabled"
	else
		service_enabled=$(get_service_state "${client_section}")
		if [ "${service_enabled}" = "0" ]; then
			echo "Error_Misconfigured"
			return
		fi

		# if any of the host status is ERROR set status to Error, otherwise status equivalent to last enabled hostname status
		hosts_list=$(get_enabled_hostnames "${client_section}")
		if [ -z "${hosts_list}" ]; then
			# no hostname configured or all are disabled
			state="Error_Misconfigured"
		else
			for host in $hosts_list; do
				last_host="${host}"
				host_state=$(get_hostname_status "${host}")
				if [ "${host_state}" =~ "Error" ]; then
					break;
				fi
			done

			if [[ "${host_state}" =~ "Error" ]]; then
				state="Error"
			else
				state="Updated"
			fi
		fi
	fi

	echo "${state}"
}

get_last_error() {
	client_section="${1}"

	enabled=$(uci -q get ddnsmngr.${client_section}.enabled)
	if [ -z "${enabled}" ] || [ "${enabled}" = "0" ]; then
		error="NO_ERROR"
	else
		service_enabled=$(get_service_state "${client_section}")
		if [ "${service_enabled}" = "0" ]; then
			echo "MISCONFIGURATION_ERROR"
			return
		fi

		# if any of the host status is ERROR set status to Error, otherwise status equivalent to last enabled hostname status
		hosts_list=$(get_enabled_hostnames "${client_section}")
		if [ -z "${hosts_list}" ]; then
			# no hostname configured or all are disabled
			error="MISCONFIGURATION_ERROR"
		else
			for host in $hosts_list; do
				last_host="${host}"
				host_state=$(get_hostname_status "${host}")
				if [ "${host_state}" =~ "Error" ]; then
					break;
				fi
			done

			if [[ "${host_state}" = "Error" ]]; then
				error="CONNECTION_ERROR"
			elif [[ "${host_state}" = "Error_dns" ]]; then
				error="DNS_ERROR"
			elif [[ "${host_state}" = "Error_auth" ]]; then
				error="AUTHENTICATION_ERROR"
			else
				error="NO_ERROR"
			fi
		fi
	fi

	echo "${error}"
}


case "$1" in
	list)
		echo '{ "last_update" : {"host":"string"}, "host_status" : {"host":"string"}, "client_status" : {"client":"string"}, "last_error" : {"client":"string"}, "agent_info" : {} }'
	;;
	call)
		case "$2" in
			last_update)
				read -r input
				json_load "${input}"
				json_get_var host_section "host"
				json_cleanup

				last_update="0001-01-01T00:00:00Z"

				if [ -z "${host_section}" ]; then
					json_init
					json_add_string "last_update" "${last_update}"
					json_dump
					exit 0
				fi

				hostname=$(uci -q get ddnsmngr.${host_section}.lookup_host)
				if [ -z "${hostname}" ]; then
					json_init
					json_add_string "last_update" "${last_update}"
					json_dump
				fi

				file_path="//.inadyn/${hostname}.cache"
				if [ -f "${file_path}" ]; then
					last_time=$(date -r "${file_path}" "+%s")
					last_update=$(date -d @"${last_time}" +'%Y-%m-%dT%H:%M:%SZ')
				fi

				json_init
				json_add_string "last_update" "${last_update}"
				json_dump
			;;
			host_status)
				read -r input
				json_load "${input}"
				json_get_var host_section "host"
				json_cleanup

				if [ -z "${host_section}" ]; then
					json_init
					json_add_string "status" "Error"
					json_dump
					exit 0
				fi

				state=$(get_hostname_status "${host_section}")
				if [ "${state}" =~ "Error" ]; then
					state="Error"
				fi

				json_init
				json_add_string "status" "${state}"
				json_dump
			;;
			client_status)
				read -r input
				json_load "${input}"
				json_get_var client_section "client"
				json_cleanup

				if [ -z "${client_section}" ]; then
					json_init
					json_add_string "status" "Error"
					json_dump
					exit 0
				fi

				state=$(get_client_status "${client_section}")

				json_init
				json_add_string "status" "${state}"
				json_dump
			;;
			last_error)
				read -r input
				json_load "${input}"
				json_get_var client_section "client"
				json_cleanup

				if [ -z "${client_section}" ]; then
					json_init
					json_add_string "last_error" "CONNECTION_ERROR"
					json_dump
					exit 0
				fi

				error=$(get_last_error "${client_section}")

				json_init
				json_add_string "last_error" "${error}"
				json_dump
			;;
			agent_info)
				ver=$(inadyn -v)
				user_agent="inadyn/${ver}"

				json_init
				json_add_string "backend" "inadyn"
				json_add_string "user_agent" "${user_agent}"
				json_dump
			;;
		esac
	;;
esac
