#!/usr/bin/env bash
set -euo pipefail

if [ "$(id -u)" -ne 0 ]; then
  echo "Please run this installer as root, for example with sudo."
  exit 1
fi

require_value() {
  local name="$1"
  local value="${!name:-}"
  if [ -z "$value" ] || [ "$value" = "$name" ]; then
    echo "Missing required value: $name"
    echo "Set STEAM_LOGIN, DB_USER, DB_PASSWORD and GUI_ADMIN_PASSWORD in the caller environment."
    echo "Do not put passwords directly in the sudo command line."
    exit 1
  fi
}

quote_environment_value() {
  local value="$1"
  value="${value//\\/\\\\}"
  value="${value//\"/\\\"}"
  printf '"%s"' "$value"
}

DEFAULT_DOWNLOAD_URL="https://acevo-server.com/downloads/acevo-server-1.0.0-SNAPSHOT.jar"

enable_debian_nonfree_sources() {
  local codename
  codename="$(. /etc/os-release && echo "${VERSION_CODENAME:-}")"

  if [ -z "$codename" ]; then
    echo "Could not detect Debian codename from /etc/os-release."
    exit 1
  fi

  cat > /etc/apt/sources.list.d/acevo-nonfree.sources <<EOF
Types: deb
URIs: http://deb.debian.org/debian
Suites: $codename ${codename}-updates
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg

Types: deb
URIs: http://security.debian.org/debian-security
Suites: ${codename}-security
Components: main contrib non-free non-free-firmware
Signed-By: /usr/share/keyrings/debian-archive-keyring.gpg
EOF
}

require_value STEAM_LOGIN
require_value DB_USER
require_value DB_PASSWORD
require_value GUI_ADMIN_PASSWORD

ACEVO_HOME="${ACEVO_HOME:-/opt/acevo}"
ACE_SERVER_HOME="${ACE_SERVER_HOME:-/opt/ace-server}"
ACEVO_CONFIG_DIR="${ACEVO_CONFIG_DIR:-/etc/acevo}"
ACEVO_PORT="${ACEVO_PORT:-8082}"
ACEVO_SERVICE_USER="${ACEVO_SERVICE_USER:-acevo}"
DOWNLOAD_URL="${DOWNLOAD_URL:-$DEFAULT_DOWNLOAD_URL}"

if [ -e "$ACEVO_CONFIG_DIR/application.properties" ] || [ -e "$ACEVO_CONFIG_DIR/install.env" ] || [ -e /etc/systemd/system/acevo.service ]; then
  echo "An existing ACEvo configuration or service was found. Back it up before running the installer again."
  exit 1
fi

echo "Installing required Debian packages..."
dpkg --add-architecture i386
enable_debian_nonfree_sources
apt-get update
apt-get install -y openjdk-21-jre steamcmd wine wine64 wine32:i386 xvfb xauth acl unzip wget curl

echo "Installing official Assetto Corsa EVO Dedicated Server..."
STEAMCMD_BIN="$(command -v steamcmd || true)"
if [ -z "$STEAMCMD_BIN" ] && [ -x /usr/games/steamcmd ]; then
  STEAMCMD_BIN="/usr/games/steamcmd"
fi
if [ -z "$STEAMCMD_BIN" ]; then
  echo "steamcmd package is installed, but the steamcmd executable was not found."
  exit 1
fi
"$STEAMCMD_BIN" +@sSteamCmdForcePlatformType windows +force_install_dir "$ACE_SERVER_HOME" +login "$STEAM_LOGIN" +app_update 4564210 validate +quit

echo "Creating ACEvo user and directories..."
if ! id "$ACEVO_SERVICE_USER" >/dev/null 2>&1; then
  useradd --system --home "$ACEVO_HOME" --shell /usr/sbin/nologin "$ACEVO_SERVICE_USER"
fi
mkdir -p "$ACEVO_HOME" "$ACEVO_CONFIG_DIR" "$ACEVO_HOME/logs" "$ACEVO_HOME/data" "$ACE_SERVER_HOME"
chown -R "$ACEVO_SERVICE_USER:$ACEVO_SERVICE_USER" "$ACEVO_HOME" "$ACE_SERVER_HOME"
ln -sfn "$ACE_SERVER_HOME" "$ACEVO_HOME/server"
chown -h "$ACEVO_SERVICE_USER:$ACEVO_SERVICE_USER" "$ACEVO_HOME/server"

echo "Downloading ACEvo Server JAR..."
wget -O "$ACEVO_HOME/acevo-server.jar" "$DOWNLOAD_URL"
chown "$ACEVO_SERVICE_USER:$ACEVO_SERVICE_USER" "$ACEVO_HOME/acevo-server.jar"

echo "Preparing Wine prefix..."
if [ ! -d "$ACEVO_HOME/.wine" ]; then
  install -d -o "$ACEVO_SERVICE_USER" -g "$ACEVO_SERVICE_USER" "$ACEVO_HOME/.wine"
  runuser -u "$ACEVO_SERVICE_USER" -- env WINEPREFIX="$ACEVO_HOME/.wine" WINEARCH=win64 xvfb-run -a wineboot
else
  echo "Keeping the existing Wine prefix at $ACEVO_HOME/.wine."
fi

echo "Writing Wine wrapper..."
cat > /usr/local/bin/acevo-wine <<EOF
#!/usr/bin/env bash
export WINEPREFIX="$ACEVO_HOME/.wine"
export WINEARCH=win64
export WINEDEBUG=-all
export XDG_RUNTIME_DIR="/tmp/acevo-runtime"
mkdir -p "\$XDG_RUNTIME_DIR"
chmod 700 "\$XDG_RUNTIME_DIR"
exec /usr/bin/xvfb-run -a /usr/bin/wine "\$@"
EOF
chmod 755 /usr/local/bin/acevo-wine

echo "Writing ACEvo configuration..."
cat > "$ACEVO_CONFIG_DIR/application.properties" <<EOF
server.port=\${ACEVO_PORT:8082}
acevo.paths.data-dir=$ACEVO_HOME

spring.datasource.url=jdbc:h2:file:\${acevo.paths.data-dir}/data/acevo-db;MODE=MariaDB;DATABASE_TO_LOWER=TRUE;CASE_INSENSITIVE_IDENTIFIERS=TRUE
spring.datasource.username=\${DB_USER:acevo}
spring.datasource.password=\${DB_PASSWORD:}
spring.datasource.driver-class-name=org.h2.Driver

acevo.dedicated-server.path=$ACE_SERVER_HOME
acevo.dedicated-server.use-wine=true
acevo.dedicated-server.wine-command=/usr/local/bin/acevo-wine
acevo.wine.binary=/usr/local/bin/acevo-wine
acevo.security.gui-admin-password-fallback=\${GUI_ADMIN_PASSWORD:}
EOF
chown root:"$ACEVO_SERVICE_USER" "$ACEVO_CONFIG_DIR/application.properties"
chmod 640 "$ACEVO_CONFIG_DIR/application.properties"

echo "Writing protected service environment file..."
cat > "$ACEVO_CONFIG_DIR/install.env" <<EOF
DB_USER=$(quote_environment_value "$DB_USER")
DB_PASSWORD=$(quote_environment_value "$DB_PASSWORD")
GUI_ADMIN_PASSWORD=$(quote_environment_value "$GUI_ADMIN_PASSWORD")
ACEVO_PORT=$(quote_environment_value "$ACEVO_PORT")
EOF
chown root:"$ACEVO_SERVICE_USER" "$ACEVO_CONFIG_DIR/install.env"
chmod 640 "$ACEVO_CONFIG_DIR/install.env"

echo "Writing systemd service..."
cat > /etc/systemd/system/acevo.service <<EOF
[Unit]
Description=ACEvo Server
After=network-online.target
Wants=network-online.target

[Service]
User=$ACEVO_SERVICE_USER
WorkingDirectory=$ACEVO_HOME
EnvironmentFile=$ACEVO_CONFIG_DIR/install.env
ExecStart=/usr/bin/java -jar $ACEVO_HOME/acevo-server.jar --spring.config.location=file:$ACEVO_CONFIG_DIR/application.properties
Restart=always
RestartSec=10

[Install]
WantedBy=multi-user.target
EOF

echo "Starting ACEvo service..."
systemctl daemon-reload
systemctl enable acevo
systemctl restart acevo

echo "Waiting for ACEvo web interface..."
sleep 8
systemctl --no-pager --full status acevo || true

echo "Running basic checks..."
ls -l "$ACE_SERVER_HOME/AssettoCorsaEVOServer.exe"
ls -l "$ACE_SERVER_HOME/cars.json" "$ACE_SERVER_HOME/events_practice.json" "$ACE_SERVER_HOME/events_race_weekend.json"
curl -I "http://127.0.0.1:$ACEVO_PORT/" || true

echo "ACEvo installation finished."
echo "Open: http://SERVER-IP:$ACEVO_PORT/"
