#!/bin/sh
set -eu
. /usr/libexec/haproxy-manager/common.sh

SYNC=0
LOCK_DIR=/var/lock/haproxy-manager.apply
LOCK_HELD=0

if [ "${1:-}" = --sync ]; then
	[ "$#" -eq 2 ] || { echo "Usage: rollback [--sync] [last|YYYYMMDD-HHMMSS]" >&2; exit 1; }
	SYNC=1
	TARGET="$2"
else
	[ "$#" -le 1 ] || { echo "Usage: rollback [--sync] [last|YYYYMMDD-HHMMSS]" >&2; exit 1; }
	TARGET="${1:-last}"
fi

release_lock() {
	[ "$LOCK_HELD" != 1 ] || operation_lock_release "$LOCK_DIR"
}

if [ "$SYNC" != 1 ]; then
	attempt=0
	while ! operation_lock_acquire "$LOCK_DIR"; do
		[ "$attempt" -lt 15 ] || { echo "Another HAProxy Manager operation is still running." >&2; exit 1; }
		attempt=$((attempt + 1))
		sleep 1
	done
	LOCK_HELD=1
	trap 'status=$?; release_lock; exit "$status"' EXIT
fi

BASE="$(backup_dir)"
[ ! -d "$BASE" ] || BASE="$(resolve_storage_dir "$BASE")" || {
	echo "Recovery point directory resolves outside /root or /mnt" >&2
	exit 1
}

if [ "$TARGET" = last ]; then
	[ -f "$BASE/LAST" ] || { echo "No LAST backup marker found" >&2; exit 1; }
	TARGET="$(basename "$(cat "$BASE/LAST")")"
fi

is_valid_backup_id "$TARGET" || { echo "Invalid backup identifier" >&2; exit 1; }
TARGET_DIR="$BASE/$TARGET"
[ -d "$TARGET_DIR" ] || { echo "Backup not found: $TARGET" >&2; exit 1; }

firewall_changed=0
uhttpd_changed=0
state_failed=0

if [ -f "$TARGET_DIR/firewall" ] && ! cmp -s "$TARGET_DIR/firewall" /etc/config/firewall; then
	atomic_install_file "$TARGET_DIR/firewall" /etc/config/firewall
	firewall_changed=1
fi
if [ -f "$TARGET_DIR/uhttpd" ] && ! cmp -s "$TARGET_DIR/uhttpd" /etc/config/uhttpd; then
	atomic_install_file "$TARGET_DIR/uhttpd" /etc/config/uhttpd
	uhttpd_changed=1
fi
[ -f "$TARGET_DIR/haproxy_manager" ] && atomic_install_file "$TARGET_DIR/haproxy_manager" /etc/config/haproxy_manager
[ -f "$TARGET_DIR/haproxy.cfg" ] && atomic_install_file "$TARGET_DIR/haproxy.cfg" "$HAPROXY_CFG"

if [ "$firewall_changed" = 1 ] && ! /etc/init.d/firewall restart >/dev/null 2>&1; then
	logger -t haproxy-manager "Firewall restart failed while restoring $TARGET"
	state_failed=1
fi

haproxy_enabled=1
haproxy_running=1
if [ -f "$TARGET_DIR/haproxy.state" ]; then
	haproxy_enabled="$(sed -n 's/^enabled=//p' "$TARGET_DIR/haproxy.state" | head -1)"
	haproxy_running="$(sed -n 's/^running=//p' "$TARGET_DIR/haproxy.state" | head -1)"
fi

if [ "$haproxy_enabled" = 1 ]; then
	if ! /etc/init.d/haproxy enable >/dev/null 2>&1; then
		logger -t haproxy-manager "Could not enable HAProxy while restoring $TARGET"
		state_failed=1
	fi
else
	if ! /etc/init.d/haproxy disable >/dev/null 2>&1; then
		logger -t haproxy-manager "Could not disable HAProxy while restoring $TARGET"
		state_failed=1
	fi
fi

restore_services() {
	local failed="$state_failed"
	if [ "$uhttpd_changed" = 1 ] && ! /etc/init.d/uhttpd restart >/dev/null 2>&1; then
		logger -t haproxy-manager "LuCI restart failed while restoring $TARGET"
		failed=1
	fi
	if [ "$haproxy_running" = 1 ]; then
		if ! /etc/init.d/haproxy restart >/dev/null 2>&1 ||
			! /etc/init.d/haproxy status >/dev/null 2>&1; then
			logger -t haproxy-manager "HAProxy restart failed while restoring $TARGET"
			failed=1
		fi
	else
		if ! /etc/init.d/haproxy stop >/dev/null 2>&1 ||
			/etc/init.d/haproxy status >/dev/null 2>&1; then
			logger -t haproxy-manager "HAProxy stop failed while restoring $TARGET"
			failed=1
		fi
	fi
	return "$failed"
}

if [ "$SYNC" = 1 ]; then
	restore_services || exit 1
else
	LOCK_HELD=0
	trap - EXIT
	(
		sleep 2
		if ! restore_services; then
			logger -t haproxy-manager "Service restoration failed for recovery point $TARGET"
		fi
		operation_lock_release "$LOCK_DIR"
	) >/dev/null 2>&1 &
	operation_lock_set_pid "$LOCK_DIR" "$!"
fi

echo "Restored backup $TARGET. Affected services will reload shortly."
