#!/bin/sh /etc/rc.common
# shellcheck shell=ash
# cspell:words CFGDIR SYSCFG USRCFG cfgfile chgrp defval getline hostlist
# cspell:words htpasswd radicale tmpconf tmpusers multifilesystem

# shellcheck disable=SC2034
START=99
USE_PROCD=1

PROG=/usr/bin/radicale3
CFGDIR=/var/etc/radicale3
SYSCFG=$CFGDIR/config
USRCFG=$CFGDIR/users
DATADIR="/var/radicale3/data"

conf_line() {
	local cfgfile="$1"
	local option="$2"
	local value="$3"

	if [ -n "$value" ]; then
		echo "$option = $value" >> "$cfgfile"
	fi
}

conf_getline() {
	local cfg="$1"
	local cfgfile="$2"
	local option="$3"
	local defval="$4"
	local boolean="$5"
	# Note: $value is used by the caller, so we do not declare it local here.
	unset value

	if [ "$boolean" != "1" ]; then
		config_get value "$cfg" "$option" "$defval"
		conf_line "$cfgfile" "$option" "$value"
	else
		config_get_bool value "$cfg" "$option" "$defval"
		# config_get_bool returns 0/1 in value
		if [ -n "$value" ]; then
			if [ "$value" -eq 1 ]; then
				conf_line "$cfgfile" "$option" "True"
			else
				conf_line "$cfgfile" "$option" "False"
			fi
		fi
	fi
}

build_hosts_line() {
	local val="$1"
	append hostlist "$val" ", "
}

conf_section() {
	local cfg="$1"
	local cfgfile="$2"
	local hostlist=""
	local value

	echo "[$cfg]" >> "$cfgfile"

	case $cfg in
	server)
		config_list_foreach "$cfg" host build_hosts_line
		conf_line "$cfgfile" hosts "$hostlist"
		conf_getline "$cfg" "$cfgfile" max_connections
		conf_getline "$cfg" "$cfgfile" max_content_length
		conf_getline "$cfg" "$cfgfile" timeout

		conf_getline "$cfg" "$cfgfile" ssl 0 1
		if [ "$value" -eq 1 ]; then
			conf_getline "$cfg" "$cfgfile" certificate
			if [ "$value" != "" ]; then
				chgrp radicale3 "$value"
				chmod g+r "$value"
			fi
			conf_getline "$cfg" "$cfgfile" key
			if [ "$value" != "" ]; then
				chgrp radicale3 "$value"
				chmod g+r "$value"
			fi
			conf_getline "$cfg" "$cfgfile" certificate_authority
			if [ "$value" != "" ]; then
				chgrp radicale3 "$value"
				chmod g+r "$value"
			fi
			conf_getline "$cfg" "$cfgfile" protocol
			conf_getline "$cfg" "$cfgfile" ciphers
		fi
		;;
	encoding)
		conf_getline "$cfg" "$cfgfile" request
		conf_getline "$cfg" "$cfgfile" stock
		;;
	auth)
		conf_getline "$cfg" "$cfgfile" "type" htpasswd
		if [ "$value" = "htpasswd" ]; then
			conf_getline "$cfg" "$cfgfile" htpasswd_filename "$USRCFG"
			conf_getline "$cfg" "$cfgfile" htpasswd_encryption plain
		fi

		conf_getline "$cfg" "$cfgfile" realm
		conf_getline "$cfg" "$cfgfile" delay
		;;
	rights)
		conf_getline "$cfg" "$cfgfile" "type"
		if [ "$value" = "from_file" ]; then
			conf_getline "$cfg" "$cfgfile" "file"
		fi
		;;
	storage)
		conf_getline "$cfg" "$cfgfile" filesystem_folder "$DATADIR"
		# Update global DATADIR if user specified a custom one, so we can mkdir it later
		if [ -n "$value" ]; then
			DATADIR="$value"
		fi
		conf_getline "$cfg" "$cfgfile" type
		conf_getline "$cfg" "$cfgfile" max_sync_token_age
		conf_getline "$cfg" "$cfgfile" hook
		;;
	web)
		conf_getline "$cfg" "$cfgfile" "type"
		;;
	logging)
		conf_getline "$cfg" "$cfgfile" level info 0
		conf_getline "$cfg" "$cfgfile" trace_on_debug 0 1
		conf_getline "$cfg" "$cfgfile" mask_passwords 1 1
		;;
	headers)
		config_get cors "$cfg" cors
		if [ -n "$cors" ]; then
			echo "Access-Control-Allow-Origin = $cors" >> "$cfgfile"
		fi
		;;
  # TODO: Add sharing configuration
	esac

	echo "" >> "$cfgfile"
}

add_missing_sections() {
	local cfgfile="$1"

	for section in server encoding auth rights storage web logging headers sharing; do
		if ! grep -q "\[$section\]" "$cfgfile"; then
			echo "[$section]" >> "$cfgfile"
			case $section in
			server)
				echo "hosts = 127.0.0.1:5232, [::1]:5232" >> "$cfgfile"
				;;
			auth)
				echo "type = htpasswd" >> "$cfgfile"
				echo "htpasswd_filename = $USRCFG" >> "$cfgfile"
				echo "htpasswd_encryption = plain" >> "$cfgfile"
				;;
			storage)
				echo "filesystem_folder = $DATADIR" >> "$cfgfile"
				;;
			esac
			echo "" >> "$cfgfile"
		fi
	done
}

add_user() {
	local cfg="$1"
	local tmpfile="$2"
	local name password

	config_get name "$cfg" name
	config_get password "$cfg" password

	[ -n "$name" ] && echo "$name:$password" >> "$tmpfile"
}

build_users() {
	local tmpfile="$1"
	config_foreach add_user user "$tmpfile"
}

build_config() {
	local tmpconf
	local tmpusers

	tmpconf=$(mktemp)
	tmpusers=$(mktemp)

	chmod 0640 "$tmpconf" "$tmpusers"

	config_load radicale3
	config_foreach conf_section section "$tmpconf"
	add_missing_sections "$tmpconf"

	build_users "$tmpusers"

	# Apply permissions
	mkdir -p "$CFGDIR"
	chmod 0750 "$CFGDIR"
	chgrp radicale3 "$CFGDIR"

	cat "$tmpconf" > "$SYSCFG"
	cat "$tmpusers" > "$USRCFG"
	chmod 0640 "$SYSCFG" "$USRCFG"
	chgrp radicale3 "$SYSCFG" "$USRCFG"

	rm -f "$tmpconf" "$tmpusers"
}

prepare_config() {
	# If custom config (/etc/radicale3/config) absent, build it from UCI
	if [ ! -f /etc/radicale3/config ]; then
		build_config
		CFG_FILE="$SYSCFG"

		# Ensure data dir exists (DATADIR might have been updated by build_config)
		mkdir -p "$DATADIR"
		chown radicale3:radicale3 "$DATADIR"
	else
		CFG_FILE="/etc/radicale3/config"
		# We assume user handles directory creation if using manual config,
		# but we could attempt it if we parsed it. simpler to leave it for now.
	fi
}

start_service() {
	prepare_config

	procd_open_instance
	procd_set_param command "$PROG" --config "$CFG_FILE"
	procd_set_param user radicale3
	procd_set_param respawn
	procd_set_param stdout 1
	procd_set_param stderr 1
	procd_close_instance
}

reload_service() {
	prepare_config
	if pgrep radicale3 >/dev/null 2>/dev/null; then
		procd_send_signal radicale3 '*' HUP
	else
		start_service
	fi
}

service_triggers() {
	procd_add_reload_trigger "radicale3"
}
