#!/bin/sh
# ---------------------------------------------------------------------------
#  Los Santos RP - installer
#
#  Puts a working server on a clean Ubuntu/Debian box: FXServer artefacts,
#  MariaDB with the schema, the resources from this repository, the keep-alive
#  supervisor and a boot entry.
#
#      sudo sh install.sh --licence cfxk_xxxxxxxx
#
#  Options
#      --licence KEY     Cfx.re server key from https://keymaster.fivem.net
#      --dir PATH        install root                     (default /opt/fivem)
#      --hostname NAME   server name shown in the list    (default from server.cfg.example)
#      --port N          game port                        (default 30120)
#      --name NAME       service name, one per server     (default fivem)
#      --db-name NAME    database                         (default rp)
#      --db-user USER    database user                    (default rp)
#      --db-pass PASS    password for that user           (default: generated)
#      --build ID        FXServer build to use            (default: latest recommended)
#      --no-start        install everything, do not start the server
# ---------------------------------------------------------------------------
set -e

DIR=/opt/fivem
LICENCE=""
HOSTNAME_=""
BUILD=""
DB_PASS=""
DB_NAME=rp
DB_USER=rp
PORT=30120
SVC=fivem
START=1
ARTIFACTS="https://runtime.fivem.net/artifacts/fivem/build_proot_linux/master/"
SRC=$(cd "$(dirname "$0")" && pwd)

while [ $# -gt 0 ]; do
  case "$1" in
    --licence|--license) LICENCE="$2"; shift 2 ;;
    --dir)               DIR="$2"; shift 2 ;;
    --hostname)          HOSTNAME_="$2"; shift 2 ;;
    --build)             BUILD="$2"; shift 2 ;;
    --db-pass)           DB_PASS="$2"; shift 2 ;;
    --db-name)           DB_NAME="$2"; shift 2 ;;
    --db-user)           DB_USER="$2"; shift 2 ;;
    --port)              PORT="$2"; shift 2 ;;
    --name)              SVC="$2"; shift 2 ;;
    --no-start)          START=0; shift ;;
    -h|--help)           sed -n '2,20p' "$0"; exit 0 ;;
    *) echo "unknown option: $1" >&2; exit 1 ;;
  esac
done

say()  { printf '\n\033[1;33m==\033[0m %s\n' "$*"; }
ok()   { printf '   \033[32mok\033[0m %s\n' "$*"; }
die()  { printf '\n\033[31mfailed:\033[0m %s\n' "$*" >&2; exit 1; }

[ "$(id -u)" = 0 ] || die "run as root (sudo sh install.sh ...)"
[ -f "$SRC/etc/schema.sql" ] || die "run this from a clone of the repository"
command -v apt-get >/dev/null || die "this installer is for Debian/Ubuntu"

# --- 1. packages -----------------------------------------------------------
say "Installing packages"
export DEBIAN_FRONTEND=noninteractive
apt-get update -qq
apt-get install -y -qq curl ca-certificates xz-utils mariadb-server >/dev/null
ok "curl, xz-utils, mariadb-server"

# --- 2. FXServer artefacts -------------------------------------------------
say "Fetching FXServer"
if [ -n "$BUILD" ]; then
  REL=$(curl -fsSL "$ARTIFACTS" | tr '>' '\n' | grep -oE "\./$BUILD-[0-9a-f]+/fx\.tar\.xz" | head -1)
  [ -n "$REL" ] || die "build $BUILD not found on $ARTIFACTS"
else
  REL=$(curl -fsSL "$ARTIFACTS" | tr '>' '\n' | grep -B4 'LATEST RECOMMENDED' \
        | grep -oE '\./[0-9]+-[0-9a-f]+/fx\.tar\.xz' | head -1)
  [ -n "$REL" ] || die "could not find the recommended build on $ARTIFACTS"
fi
URL="$ARTIFACTS${REL#./}"
BUILD_ID=$(echo "$REL" | grep -oE '[0-9]+' | head -1)

mkdir -p "$DIR/server" "$DIR/data/resources" "$DIR/bin" "$DIR/logs" "$DIR/etc"
if [ -x "$DIR/server/run.sh" ] && [ -f "$DIR/server/.build" ] && [ "$(cat "$DIR/server/.build")" = "$BUILD_ID" ]; then
  ok "build $BUILD_ID already installed"
else
  TMP=$(mktemp -d)
  curl -fL# "$URL" -o "$TMP/fx.tar.xz" || die "download failed: $URL"
  rm -rf "$DIR/server"; mkdir -p "$DIR/server"
  tar xJf "$TMP/fx.tar.xz" -C "$DIR/server"
  rm -rf "$TMP"
  chmod +x "$DIR/server/run.sh"
  echo "$BUILD_ID" > "$DIR/server/.build"
  ok "build $BUILD_ID unpacked into $DIR/server"
fi

# --- 3. database -----------------------------------------------------------
say "Preparing the database"
if [ ! -f /etc/init.d/mariadb ] && [ ! -d /run/systemd/system ]; then
  die "no init system found for mariadb"
fi
if [ -d /run/systemd/system ]; then
  systemctl enable --now mariadb >/dev/null 2>&1 || true
else
  service mariadb start >/dev/null 2>&1 || true
fi
i=0
while ! mysqladmin ping >/dev/null 2>&1; do
  i=$((i+1)); [ $i -gt 60 ] && die "mariadb did not start"
  sleep 1
done

if [ -z "$DB_PASS" ]; then
  if [ -f "$DIR/data/secrets.cfg" ]; then
    DB_PASS=$(sed -n 's/^set rp_db_pass "\(.*\)"$/\1/p' "$DIR/data/secrets.cfg" | head -1)
  fi
  [ -n "$DB_PASS" ] || DB_PASS=$(head -c 24 /dev/urandom | base64 | tr -dc 'A-Za-z0-9' | cut -c1-24)
fi

mysql -e "CREATE DATABASE IF NOT EXISTS \`$DB_NAME\` CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;"
mysql -e "CREATE USER IF NOT EXISTS '$DB_USER'@'127.0.0.1' IDENTIFIED BY '$DB_PASS';"
mysql -e "ALTER USER '$DB_USER'@'127.0.0.1' IDENTIFIED BY '$DB_PASS';"
mysql -e "GRANT SELECT, INSERT, UPDATE, DELETE ON \`$DB_NAME\`.* TO '$DB_USER'@'127.0.0.1'; FLUSH PRIVILEGES;"
mysql "$DB_NAME" < "$SRC/etc/schema.sql"
ok "database $DB_NAME, user $DB_USER@127.0.0.1, schema applied"

# --- 4. resources and configuration ---------------------------------------
say "Installing the server files"
rm -rf "$DIR/data/resources/[rp]"
mkdir -p "$DIR/data/resources"
cp -r "$SRC/resources/[rp]" "$DIR/data/resources/"
cp "$SRC/bin/supervise.sh" "$DIR/bin/"
sed "s|/run/fivem.stdin|/run/$SVC.stdin|" "$SRC/bin/rcon" > "$DIR/bin/rcon"
chmod +x "$DIR/bin/supervise.sh" "$DIR/bin/rcon"
cp "$SRC/etc/schema.sql" "$DIR/etc/schema.sql"
ln -sf "$DIR/bin/rcon" "/usr/local/bin/$([ "$SVC" = fivem ] && echo rcon || echo "rcon-$SVC")"

if [ -f "$DIR/data/server.cfg" ]; then
  ok "server.cfg kept (already present)"
else
  sed -e "s|exec /opt/fivem/data/secrets.cfg|exec $DIR/data/secrets.cfg|" \
      -e "s|0.0.0.0:30120|0.0.0.0:$PORT|g" \
      "$SRC/server.cfg.example" > "$DIR/data/server.cfg"
  [ -n "$HOSTNAME_" ] && sed -i "s|^sv_hostname .*|sv_hostname \"$HOSTNAME_\"|;s|^sets sv_projectName .*|sets sv_projectName \"$HOSTNAME_\"|" "$DIR/data/server.cfg"
  ok "server.cfg written"
fi

if [ -z "$LICENCE" ] && [ -f "$DIR/data/secrets.cfg" ]; then
  LICENCE=$(sed -n 's/^sv_licenseKey "\(.*\)"$/\1/p' "$DIR/data/secrets.cfg" | head -1)
fi
cat > "$DIR/data/secrets.cfg" <<EOF
# Licence key and database credentials. Never commit this file.
sv_licenseKey "${LICENCE:-cfxk_your_key_here}"

set rp_db_host "127.0.0.1"
set rp_db_port "3306"
set rp_db_user "$DB_USER"
set rp_db_pass "$DB_PASS"
set rp_db_name "$DB_NAME"
EOF
chmod 600 "$DIR/data/secrets.cfg"
ok "secrets.cfg written (mode 600)"

# --- 5. boot entry ---------------------------------------------------------
say "Setting up start on boot"
sed -e "s|^DATA=.*|DATA=$DIR/data|" -e "s|^SERVER=.*|SERVER=$DIR/server|" \
    -e "s|^LOG=.*|LOG=$DIR/logs/server.log|" -e "s|^NAME=.*|NAME=$SVC|" \
    -e "s|/opt/fivem/bin/supervise.sh|$DIR/bin/supervise.sh|" \
    "$SRC/bin/fivem.init" > "/etc/init.d/$SVC"
chmod +x "/etc/init.d/$SVC"

if [ -d /run/systemd/system ]; then
  cat > "/etc/systemd/system/$SVC.service" <<EOF
[Unit]
Description=Los Santos RP (FXServer)
After=network-online.target mariadb.service
Wants=mariadb.service

[Service]
Type=simple
WorkingDirectory=$DIR/data
ExecStart=$DIR/bin/supervise.sh $SVC $DIR/logs/server.log $DIR/server/run.sh +set citizen_dir $DIR/server/alpine/opt/cfx-server/citizen/ +exec $DIR/data/server.cfg
KillMode=mixed
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF
  systemctl daemon-reload
  systemctl enable "$SVC" >/dev/null 2>&1
  ok "systemd unit $SVC.service"
elif [ -d /etc/redl/enabled ]; then
  # REDL VDS: no systemd, the platform starts whatever is marked here
  touch "/etc/redl/enabled/$SVC" /etc/redl/enabled/mariadb
  ok "marked in /etc/redl/enabled (REDL VDS autostart)"
elif [ -f /etc/redl/enabled ]; then
  grep -qx "$SVC" /etc/redl/enabled || echo "$SVC" >> /etc/redl/enabled
  grep -qx mariadb /etc/redl/enabled || echo mariadb >> /etc/redl/enabled
  ok "marked in /etc/redl/enabled (REDL VDS autostart)"
else
  command -v update-rc.d >/dev/null && update-rc.d "$SVC" defaults >/dev/null 2>&1 || true
  ok "/etc/init.d/$SVC installed"
fi

# --- 6. start --------------------------------------------------------------
if [ "$START" = 0 ]; then
  say "Done (not started, --no-start)"
  exit 0
fi
if [ -z "$LICENCE" ]; then
  say "Done"
  echo "   No licence key given. Get a free one at https://keymaster.fivem.net,"
  echo "   put it into $DIR/data/secrets.cfg and run:  service $SVC start"
  exit 0
fi

say "Starting the server"
if [ -d /run/systemd/system ]; then systemctl restart "$SVC"; else service "$SVC" restart >/dev/null; fi

i=0
while [ $i -lt 90 ]; do
  if grep -q "Authenticated with cfx.re Nucleus" "$DIR/logs/server.log" 2>/dev/null; then
    ok "server is up and registered with Cfx"
    grep -q "\[selftest\] data path OK" "$DIR/logs/server.log" && ok "self-test passed: the data path works"
    IP=$(curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null || echo "<server ip>")
    printf '\n   connect %s:%s\n   logs:  tail -f %s\n   console: rcon status\n\n' "$IP" "$PORT" "$DIR/logs/server.log"
    exit 0
  fi
  if grep -qE "Could not authenticate server license key|invalid license key|Failed to verify" "$DIR/logs/server.log" 2>/dev/null; then
    if [ -d /run/systemd/system ]; then systemctl stop "$SVC"; else service "$SVC" stop >/dev/null 2>&1; fi
    die "the licence key was refused - get one at https://keymaster.fivem.net, put it into $DIR/data/secrets.cfg and run: service $SVC start"
  fi
  i=$((i+1)); sleep 2
done
die "the server did not come up in 3 minutes - see $DIR/logs/server.log"
