#!/bin/sh /etc/rc.common

START=99
STOP=01

USE_PROCD=1

log() {
	echo "${@}"|logger -t crun.init -p info
}

is_container_running() {
	crun list |tail -n +2|grep -wq "^${1}"
	return $?
}


configure_lxc_container() {
	local requested_state name ctype du_status BUNDLE section

	ctype="${1}"
	name="${2}"
	requested_state="${3}"
	du_status="${4}"
	BUNDLE="${5}"
	section="${6}"

	if [ "${ctype}" != "lxc" ]; then
		return 0;
	fi

	if [ "${du_status}" = "Uninstalling" ]; then
		lxc-stop -q -k "${name}"
		if [ -d "${BUNDLE:?}/${name:?}" ]; then
			rm -rf "${BUNDLE:?}/${name:?}"
		fi

		# If directory still exists then uninstall failed
		if [ -d "${BUNDLE}/${name}" ]; then
			uci_set ocicontainer "${section}" du_status Uninstalling_failed
			uci_set ocicontainer "${section}" fault_string "Failed to remove ${BUNDLE}/${name}"
			log "LXC container ${name} remove failed"
		else
			uci_set ocicontainer "${section}" du_status Uninstalling_success
			log "LXC container ${name} removed"
		fi

		return 0;
	fi

	if [ "${requested_state}" = "Idle" ]; then
		lxc-stop -q -k "${name}"
	elif [ "${requested_state}" = "Active" ]; then
		lxc-start -q "${name}" >/dev/null 2>&1
	fi
}

configure_crun_container() {
	local name type autostart du_status requested_state url username password capability envlist
	local BRIDGE BUNDLE BOOT PERM
	local RUNNER="/etc/swmodd/run.sh"

	BUNDLE="${2}"
	BRIDGE="${3}"
	BOOT="${4}"
	TIMEOUT="${5}"

	config_get name "${1}" name ""
	config_get type "${1}" type ""
	config_get_bool autostart "${1}" autostart 1
	config_get du_status "${1}" du_status ""
	config_get requested_state "${1}" requested_state ""
	config_get url "${1}" url ""
	config_get username "${1}" username ""
	config_get password "${1}" password ""
	config_get capability "${1}" capability ""
	config_get envlist "${1}" env_var ""

	if [ -n "${envlist}" ]; then
		envlist="${envlist// /;}"
	fi

	if [ -n "${capability}" ]; then
		PERM="-p ${capability// /,}"
	fi

	if [ -z "${name}" ] || [ -z "${type}" ] || [ -z "${du_status}" ]; then
		return 0;
	fi

	if [ "${type}" != "crun" ]; then
		configure_lxc_container "${type}" "${name}" "${requested_state}" "${du_status}" "${BUNDLE}" "${1}"
		return 0;
	fi

	if [ "${du_status}" = "Installing" ]; then
		local result
		log "Pull image from registry"
		uci_set ocicontainer "${1}" du_status Installing_start
		uci_set ocicontainer "${1}" username ""
		uci_set ocicontainer "${1}" password ""
		result=$(${RUNNER} -b "${BUNDLE}" -n "${name}" -r "${url}" -l "${username}:${password}" -t "${TIMEOUT}")
		if [ "$?" -eq 0 ]; then
			result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_description")
			if [ "${result}" != "null" ]; then
				uci_set ocicontainer "${1}" description "${result}"
			fi

			result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_vendor")
			if [ "${result}" != "null" ]; then
				uci_set ocicontainer "${1}" vendor "${result}"
			fi

			result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_version")
			if [ "${result}" != "null" ]; then
				uci_set ocicontainer "${1}" version "${result}"
			fi

			uci_set ocicontainer "${1}" du_status Installing_success
			du_status="Installed"
		else
			uci_set ocicontainer "${1}" du_status Installing_failed
			uci_set ocicontainer "${1}" fault_string "${result}"
			return 0;
		fi
	fi

	if [ "${du_status}" = "Uninstalling" ]; then
		ubus call service delete "{\"name\":\"crun\",\"instance\":\"${name}\"}"
		if is_container_running "${name}"; then
			crun kill --all "${name}" 9
		fi
		${RUNNER} -c -n "${name}"
		if [ -d "${BUNDLE:?}/${name:?}" ]; then
			rm -rf "${BUNDLE:?}/${name:?}"
		fi

		# If directory still exists then uninstall failed
		if [ -d "${BUNDLE}/${name}" ]; then
			uci_set ocicontainer "${1}" du_status Uninstalling_failed
			uci_set ocicontainer "${1}" fault_string "Failed to remove ${BUNDLE}/${name}"
		else
			uci_set ocicontainer "${1}" du_status Uninstalling_success
		fi
		# Delete the uci config section after uninstall
		log "CRUN container ${name} removed"
		return 0;
	fi

	if [ ! -d "${BUNDLE:?}/${name:?}" ]; then
		log "Crun container {${BUNDLE:?}/${name:?}} not available"
		return 0;
	fi

	if [ "${du_status}" != "Installed" ]; then
		return 0;
	fi

	if [ "${BOOT}" -eq "1" ]; then
		if [ "${autostart}" -eq 1 ]; then
			${RUNNER} -U -b "${BUNDLE}" -n "${name}" -e "${envlist}" ${PERM}
			result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_description")
			if [ "${result}" != "null" ]; then
				uci_set ocicontainer "${1}" description "${result}"
			fi

			result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_vendor")
			if [ "${result}" != "null" ]; then
				uci_set ocicontainer "${1}" vendor "${result}"
			fi

			result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_version")
			if [ "${result}" != "null" ]; then
				uci_set ocicontainer "${1}" version "${result}"
			fi
			uci_set ocicontainer "${1}" requested_state "Active"
		else
			uci_set ocicontainer "${1}" requested_state "Idle"
			return 0;
		fi
	else
		log "Container [$name] req_status [${requested_state}]"
		if [ "${requested_state}" = "Idle" ]; then
			if is_container_running "${name}"; then
				crun pause "${name}"
			else
				return 0;
			fi
		elif [ "${requested_state}" = "Active" ]; then
			if is_container_running "${name}"; then
				${RUNNER} -u -n "${name}" -i "${BRIDGE}" ${PERM}
				crun resume "${name}"
			else
				${RUNNER} -U -b "${BUNDLE}" -n "${name}" -e "${envlist}" ${PERM}
				result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_description")
				if [ "${result}" != "null" ]; then
					uci_set ocicontainer "${1}" description "${result}"
				fi

				result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_vendor")
				if [ "${result}" != "null" ]; then
					uci_set ocicontainer "${1}" vendor "${result}"
				fi

				result=$(cat ${BUNDLE}/${name}/config.json |jq ".annotations.org_opencontainers_image_version")
				if [ "${result}" != "null" ]; then
					uci_set ocicontainer "${1}" version "${result}"
				fi
			fi
		else
			return 0;
		fi
	fi

        procd_open_instance "${name}"
        procd_set_param stdout 1
        procd_set_param stderr 1
        procd_set_param command "${RUNNER}"
        procd_append_param command -b "${BUNDLE}" -n "${name}" -i "${BRIDGE}"
        #procd_set_param respawn
        procd_close_instance "${name}"
}

boot() {
	start "bootstrap"
}

start_service() {
	local bundle root env bridge boot

	# Check if crun present
	if ! command -v crun >/dev/null 2>&1; then
		log "CRUN binary not found"
		return 0;
	fi

	if [ "${1}" = "bootstrap" ]; then
		boot=1
	else
		boot=0
	fi

	# crun default runtime directory /run, if not present then create
	if [ ! -d "/run" ]; then
		if [ ! -L "/run" ]; then
			ln -fs /var/run /run
		fi
	fi

	config_load swmodd
	config_get root globals root ""
	config_get bridge globals lan_bridge "br-lan"
	config_get timeout globals oci_pull_timeout "10"

	env=$(uci -q get swmodd.@execenv[0].name)
	if [ -z "${root}" ] || [ -z "${bridge}" ]; then
		log "# Base bundle root[$root] or bridge[$bridge] not defined"
		return 0;
	fi

	bundle="${root}/${env}"
	if [ -f "${bundle}/ocicontainer" ]; then
		UCI_CONFIG_DIR="${bundle}"
		config_load ocicontainer
		config_foreach configure_crun_container du_eu_assoc "${bundle}" "${bridge}" "${boot}" "${timeout}"
		uci_commit ocicontainer

		# Add a timer for DuStateChange!
		(sleep 5 && ubus -t 5 call swmodules reload) &
	else
		log "${bundle}/ocicontainer not present"
	fi
}

stop_service() {
	local cid

	cid="$(crun list|tail -n +2 |awk '{printf $1 " "}')"
	for f in $cid; do
		crun kill --all "${f}" 9
	done
}

reload_service() {
        start
}

service_triggers() {
	procd_add_reload_trigger "crun" "network"
}
