#!/bin/sh

. /usr/share/gecoosac/common.sh

changed=0
LEGACY_UPLOAD_DIR=/etc/gecoosac/upload
OLD_CRT_FILE=/etc/gecoosac/tls/1.crt
OLD_KEY_FILE=/etc/gecoosac/tls/1.key
CONFIG_COMPAT=2

ensure_section() {
	uci -q get gecoosac.config >/dev/null && return 0
	uci -q set gecoosac.config=gecoosac || return 1
	changed=1
}

set_default() {
	local option="$1"
	local value="$2"

	uci -q get "gecoosac.config.${option}" >/dev/null && return 0
	uci -q set "gecoosac.config.${option}=${value}" || return 1
	changed=1
}

normalize_upload_dir() {
	local upload_dir normalized

	upload_dir="$(uci -q get gecoosac.config.upload_dir)"
	[ -n "$upload_dir" ] || return 0
	normalized="$(normalize_path "$upload_dir")" || return 0
	case "$normalized" in
		/etc/gecoosac/upload) normalized="$DEFAULT_UPLOAD_DIR" ;;
		*) is_safe_upload_dir "$normalized" || return 0 ;;
	esac

	[ "$upload_dir" = "$normalized" ] && return 0
	uci -q set "gecoosac.config.upload_dir=${normalized}" || return 1
	changed=1
}

configured_path_in_legacy_upload() {
	local physical="$1" option role path

	for option in db_dir piddir crt_file key_file; do
		path="$(uci -q get "gecoosac.config.${option}")"
		[ -n "$path" ] || continue
		case "$option" in
			db_dir) role=db ;;
			piddir) role=pid ;;
			*) role="file" ;;
		esac
		protected_path_in_dir "$path" "$role" "$physical" "$LEGACY_UPLOAD_DIR" "$physical"
		case "$?" in
			1) ;;
			*) return 0 ;;
		esac
	done

	return 1
}

cleanup_legacy_upload_dir() {
	local physical mount_state

	[ -e "$LEGACY_UPLOAD_DIR" ] || [ -L "$LEGACY_UPLOAD_DIR" ] || return 0
	if [ ! -d "$LEGACY_UPLOAD_DIR" ] || [ -L "$LEGACY_UPLOAD_DIR" ]; then
		logger -t gecoosac "refusing to remove unsafe legacy upload path: $LEGACY_UPLOAD_DIR"
		return 0
	fi
	physical="$(readlink -f "$LEGACY_UPLOAD_DIR" 2>/dev/null)" || {
		logger -t gecoosac "unable to resolve legacy upload path: $LEGACY_UPLOAD_DIR"
		return 0
	}
	physical="$(normalize_path "$physical")" || return 0
	if configured_path_in_legacy_upload "$physical"; then
		logger -t gecoosac "preserving legacy upload path referenced by configuration: $LEGACY_UPLOAD_DIR"
		return 0
	fi

	path_has_mount "$physical"
	mount_state="$?"
	case "$mount_state" in
		0)
			logger -t gecoosac "preserving legacy upload path containing a mount: $LEGACY_UPLOAD_DIR"
			return 0
		;;
		2)
			logger -t gecoosac "unable to validate legacy upload mounts: $LEGACY_UPLOAD_DIR"
			return 0
		;;
	esac

	# Apply the same ownership and ancestor-symlink policy as RPC cleanup.
	# Relocated legacy directories are preserved for manual review.
	if ! is_secure_upload_dir "$LEGACY_UPLOAD_DIR" || [ "$physical" != "$LEGACY_UPLOAD_DIR" ]; then
		logger -t gecoosac "refusing to remove unsafe legacy upload path: $LEGACY_UPLOAD_DIR"
		return 0
	fi
	rm -rf "$physical" || {
		logger -t gecoosac "failed to remove legacy upload path: $LEGACY_UPLOAD_DIR"
		return 1
	}
	[ ! -e "$LEGACY_UPLOAD_DIR" ] && [ ! -L "$LEGACY_UPLOAD_DIR" ]
}

normalize_dir_option() {
	local option="$1"
	local validator="$2"
	local value normalized upload_dir

	value="$(uci -q get "gecoosac.config.${option}")"
	[ -n "$value" ] || return 0
	upload_dir="$(uci -q get gecoosac.config.upload_dir)"
	[ -n "$upload_dir" ] || upload_dir="$DEFAULT_UPLOAD_DIR"

	if "$validator" "$value" "$upload_dir"; then
		normalized="$(normalize_path "$value")"
	else
		return 0
	fi

	[ "$value" = "$normalized" ] && return 0
	uci -q set "gecoosac.config.${option}=${normalized}" || return 1
	changed=1
}

is_managed_cert_path() {
	case "$1" in
		""|"$2"|"$3") return 0 ;;
	esac
	return 1
}

is_regular_file_or_absent() {
	[ ! -e "$1" ] && [ ! -L "$1" ] && return 0
	[ -f "$1" ] && [ ! -L "$1" ] && is_secure_upload_dir "${1%/*}"
}

migrate_default_certificates() {
	local crt_file key_file path

	crt_file="$(uci -q get gecoosac.config.crt_file)"
	key_file="$(uci -q get gecoosac.config.key_file)"
	is_managed_cert_path "$crt_file" "$OLD_CRT_FILE" "$DEFAULT_CRT_FILE" || return 0
	is_managed_cert_path "$key_file" "$OLD_KEY_FILE" "$DEFAULT_KEY_FILE" || return 0

	for path in "$OLD_CRT_FILE" "$OLD_KEY_FILE" "$DEFAULT_CRT_FILE" "$DEFAULT_KEY_FILE"; do
		is_regular_file_or_absent "$path" || {
			logger -t gecoosac "refusing unsafe certificate migration path: $path"
			return 1
		}
	done

	# Managed certificates are regenerated when HTTPS next starts.
	rm -f "$OLD_CRT_FILE" "$OLD_KEY_FILE" "$DEFAULT_CRT_FILE" "$DEFAULT_KEY_FILE" || return 1

	if [ "$crt_file" != "$DEFAULT_CRT_FILE" ]; then
		uci -q set "gecoosac.config.crt_file=${DEFAULT_CRT_FILE}" || return 1
		changed=1
	fi
	if [ "$key_file" != "$DEFAULT_KEY_FILE" ]; then
		uci -q set "gecoosac.config.key_file=${DEFAULT_KEY_FILE}" || return 1
		changed=1
	fi
}

migrate_config() {
	local compat

	compat="$(uci -q get gecoosac.config.config_compat)"
	[ "$compat" = "$CONFIG_COMPAT" ] && return 0
	migrate_default_certificates || return 1
	cleanup_legacy_upload_dir || return 1
	uci -q set "gecoosac.config.config_compat=${CONFIG_COMPAT}" || return 1
	changed=1
}

ensure_section || exit 1
migrate_config || exit 1
normalize_upload_dir || exit 1
normalize_dir_option db_dir is_safe_db_dir || exit 1
normalize_dir_option piddir is_safe_pid_dir || exit 1
set_default enabled 0 || exit 1
set_default port 60650 || exit 1
set_default isonlyoneprot 1 || exit 1
set_default m_port 8080 || exit 1
set_default https 0 || exit 1
set_default crt_file "$DEFAULT_CRT_FILE" || exit 1
set_default key_file "$DEFAULT_KEY_FILE" || exit 1
set_default upload_dir "$DEFAULT_UPLOAD_DIR" || exit 1
set_default db_dir "$DEFAULT_DB_DIR" || exit 1
set_default piddir "$DEFAULT_PID_DIR" || exit 1
set_default lang zh || exit 1
set_default debug 0 || exit 1
# Preserve the previous package behavior for upgraded configs that never had showtip.
set_default showtip 0 || exit 1
set_default log 0 || exit 1

if [ "$changed" = "1" ]; then
	uci -q commit gecoosac || exit 1
fi

exit 0
