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

DOWNLOAD_URL="https://download.sentralogic.id/filesystem-shell-relay-20260721-170522.tar.gz"
TMP_ARCHIVE="/tmp/filesystem-shell-relay-20260721-170522.tar.gz"
INSTALL_DIR="/opt/filesystem-shell-relay"
APP_DLL="$INSTALL_DIR/FileSystemShellMcp.Relay.Server.dll"
APP_PORT="5300"
SERVICE_USER="filesystem-shell"
PROGRAM="scryfer-relay"
SUPERVISOR_CONF="/etc/supervisor/conf.d/$PROGRAM.conf"
LOG_DIR="/var/log/$PROGRAM"

info() { printf '\n[INFO] %s\n' "$*"; }
warn() { printf '\n[WARN] %s\n' "$*" >&2; }
die()  { printf '\n[ERROR] %s\n' "$*" >&2; exit 1; }

confirm() {
  local answer
  read -r -p "$1 [y/N]: " answer
  case "$answer" in y|Y|yes|YES|Yes) return 0 ;; *) return 1 ;; esac
}

must_confirm() {
  confirm "$1" || die "Cancelled by user."
}

run_step() {
  local prompt="$1"
  shift
  must_confirm "$prompt"
  "$@"
}

[[ $EUID -eq 0 ]] || die "Run as root: sudo /home/install-scryfer-relay.sh"

cat <<EOF
============================================================
 Scryfer Relay Installer
============================================================
Archive : $DOWNLOAD_URL
Target  : $INSTALL_DIR
Port    : $APP_PORT

Every installation and configuration action requires approval.
EOF

must_confirm "Begin installation checks?"

if command -v apt-get >/dev/null 2>&1; then
  PM=apt
elif command -v dnf >/dev/null 2>&1; then
  PM=dnf
elif command -v yum >/dev/null 2>&1; then
  PM=yum
else
  die "Supported package manager not found (apt, dnf, yum)."
fi

install_packages() {
  if [[ $PM == apt ]]; then
    run_step "Refresh APT package metadata?" apt-get update
    run_step "Install packages: $* ?" apt-get install -y "$@"
  elif [[ $PM == dnf ]]; then
    run_step "Install packages: $* ?" dnf install -y "$@"
  else
    run_step "Install packages: $* ?" yum install -y "$@"
  fi
}

if ! command -v curl >/dev/null 2>&1 && ! command -v wget >/dev/null 2>&1; then
  install_packages curl
fi

command -v tar >/dev/null 2>&1 || install_packages tar gzip

if ! command -v supervisorctl >/dev/null 2>&1; then
  install_packages supervisor
fi

if command -v systemctl >/dev/null 2>&1; then
  run_step "Enable Supervisor at boot?" systemctl enable supervisor
  run_step "Start or restart Supervisor?" systemctl restart supervisor
fi

command -v nginx >/dev/null 2>&1 || install_packages nginx

if command -v systemctl >/dev/null 2>&1; then
  run_step "Enable Nginx at boot?" systemctl enable nginx
  run_step "Start or restart Nginx?" systemctl restart nginx
fi

if ! command -v certbot >/dev/null 2>&1; then
  install_packages certbot python3-certbot-nginx
fi

if ! command -v dotnet >/dev/null 2>&1; then
  must_confirm "Install ASP.NET Core runtime 8.0 from configured repositories?"
  if [[ $PM == apt ]]; then
    apt-get install -y aspnetcore-runtime-8.0
  elif [[ $PM == dnf ]]; then
    dnf install -y aspnetcore-runtime-8.0
  else
    yum install -y aspnetcore-runtime-8.0
  fi
fi

must_confirm "Download the relay archive?"
rm -f "$TMP_ARCHIVE"
if command -v curl >/dev/null 2>&1; then
  curl -fL --retry 3 --connect-timeout 20 -o "$TMP_ARCHIVE" "$DOWNLOAD_URL"
else
  wget -O "$TMP_ARCHIVE" "$DOWNLOAD_URL"
fi

run_step "Validate the downloaded archive?" tar -tzf "$TMP_ARCHIVE"

if ! id "$SERVICE_USER" >/dev/null 2>&1; then
  must_confirm "Create restricted system user $SERVICE_USER?"
  useradd --system --no-create-home --shell /usr/sbin/nologin "$SERVICE_USER"
fi

if [[ -d $INSTALL_DIR ]]; then
  BACKUP="$INSTALL_DIR.backup-$(date +%Y%m%d-%H%M%S)"
  run_step "Move existing installation to $BACKUP?" mv "$INSTALL_DIR" "$BACKUP"
fi

run_step "Extract the application into /opt?" tar -xzf "$TMP_ARCHIVE" -C /opt
[[ -f $APP_DLL ]] || die "Application DLL not found: $APP_DLL"

run_step "Set application ownership to $SERVICE_USER?" chown -R "$SERVICE_USER:$SERVICE_USER" "$INSTALL_DIR"

must_confirm "Set application file permissions?"
find "$INSTALL_DIR" -type d -exec chmod 755 {} \;
find "$INSTALL_DIR" -type f -exec chmod 644 {} \;
[[ -f "$INSTALL_DIR/FileSystemShellMcp.Relay.Server" ]] && chmod 755 "$INSTALL_DIR/FileSystemShellMcp.Relay.Server"

must_confirm "Create Supervisor log directory $LOG_DIR?"
mkdir -p "$LOG_DIR"
chown "$SERVICE_USER:$SERVICE_USER" "$LOG_DIR"

if [[ -f $SUPERVISOR_CONF ]]; then
  SUP_BACKUP="$SUPERVISOR_CONF.backup-$(date +%Y%m%d-%H%M%S)"
  run_step "Back up existing Supervisor config to $SUP_BACKUP?" cp -a "$SUPERVISOR_CONF" "$SUP_BACKUP"
fi

must_confirm "Write Supervisor configuration $SUPERVISOR_CONF?"
cat > "$SUPERVISOR_CONF" <<EOF
[program:$PROGRAM]
command=/usr/bin/dotnet $APP_DLL
directory=$INSTALL_DIR
user=$SERVICE_USER
environment=ASPNETCORE_ENVIRONMENT="Production",ASPNETCORE_URLS="http://127.0.0.1:$APP_PORT"
autostart=true
autorestart=true
startsecs=5
startretries=5
stopsignal=TERM
stopwaitsecs=30
stopasgroup=true
killasgroup=true
stdout_logfile=$LOG_DIR/out.log
stderr_logfile=$LOG_DIR/err.log
stdout_logfile_maxbytes=10MB
stderr_logfile_maxbytes=10MB
stdout_logfile_backups=5
stderr_logfile_backups=5
EOF

run_step "Run supervisorctl reread?" supervisorctl reread
run_step "Run supervisorctl update?" supervisorctl update

if supervisorctl status "$PROGRAM" 2>/dev/null | grep -q RUNNING; then
  run_step "Restart $PROGRAM?" supervisorctl restart "$PROGRAM"
else
  run_step "Start $PROGRAM?" supervisorctl start "$PROGRAM"
fi

run_step "Display Supervisor status?" supervisorctl status "$PROGRAM"

must_confirm "Scan Nginx configuration for installed domains?"
mapfile -t HOSTS < <(
  nginx -T 2>/dev/null |
  awk '/^[[:space:]]*server_name[[:space:]]+/ {for(i=2;i<=NF;i++) print $i}' |
  sed 's/;//g' |
  grep -Ev '^(_|localhost|default_server|\*\.)$' |
  grep -Ev '^[0-9.]+$' |
  grep -E '^[A-Za-z0-9.-]+\.[A-Za-z]{2,}$' |
  sort -u
)

if ((${#HOSTS[@]})); then
  printf '\nDetected Nginx hostnames:\n'
  for i in "${!HOSTS[@]}"; do
    printf '  %d) %s\n' "$((i+1))" "${HOSTS[$i]}"
  done
else
  warn "No usable hostname was detected."
fi

printf '\nEnter the base domain, for example example.com.\n'
read -r -p "Base domain: " BASE_DOMAIN
BASE_DOMAIN="${BASE_DOMAIN,,}"
BASE_DOMAIN="${BASE_DOMAIN#http://}"
BASE_DOMAIN="${BASE_DOMAIN#https://}"
BASE_DOMAIN="${BASE_DOMAIN%%/*}"
BASE_DOMAIN="${BASE_DOMAIN%.}"

[[ $BASE_DOMAIN =~ ^[a-z0-9]([a-z0-9.-]*[a-z0-9])?\.[a-z]{2,}$ ]] || die "Invalid base domain: $BASE_DOMAIN"

DOMAIN="scryfer.$BASE_DOMAIN"
printf '\nProposed hostname: %s\n' "$DOMAIN"
must_confirm "Use $DOMAIN?"

NGINX_AVAILABLE="/etc/nginx/sites-available"
NGINX_ENABLED="/etc/nginx/sites-enabled"
NGINX_SITE="$NGINX_AVAILABLE/$DOMAIN"
NGINX_LINK="$NGINX_ENABLED/$DOMAIN"

mkdir -p "$NGINX_AVAILABLE" "$NGINX_ENABLED"

if [[ -f $NGINX_SITE ]]; then
  NGINX_BACKUP="$NGINX_SITE.backup-$(date +%Y%m%d-%H%M%S)"
  run_step "Back up existing Nginx site to $NGINX_BACKUP?" cp -a "$NGINX_SITE" "$NGINX_BACKUP"
fi

must_confirm "Write Nginx configuration for $DOMAIN?"
cat > "$NGINX_SITE" <<EOF
server {
    listen 80;
    listen [::]:80;
    server_name $DOMAIN;

    client_max_body_size 10m;

    location / {
        proxy_pass http://127.0.0.1:$APP_PORT;
        proxy_http_version 1.1;
        proxy_set_header Host \$host;
        proxy_set_header X-Real-IP \$remote_addr;
        proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto \$scheme;
        proxy_set_header Upgrade \$http_upgrade;
        proxy_set_header Connection "upgrade";
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
    }
}
EOF

if [[ -e $NGINX_LINK || -L $NGINX_LINK ]]; then
  run_step "Remove existing enabled-site entry $NGINX_LINK?" rm -f "$NGINX_LINK"
fi

run_step "Enable Nginx site $DOMAIN?" ln -s "$NGINX_SITE" "$NGINX_LINK"
run_step "Test Nginx configuration?" nginx -t

if command -v systemctl >/dev/null 2>&1; then
  run_step "Reload Nginx?" systemctl reload nginx
else
  run_step "Reload Nginx?" nginx -s reload
fi

must_confirm "Check DNS resolution for $DOMAIN?"
if command -v getent >/dev/null 2>&1; then
  getent ahosts "$DOMAIN" || warn "DNS does not resolve yet for $DOMAIN."
elif command -v host >/dev/null 2>&1; then
  host "$DOMAIN" || warn "DNS does not resolve yet for $DOMAIN."
else
  warn "No DNS lookup utility is available."
fi

if confirm "Run Certbot for $DOMAIN now?"; then
  certbot --nginx -d "$DOMAIN"
else
  warn "Certbot skipped; HTTPS is not configured."
fi

if confirm "Run final validation checks?"; then
  supervisorctl status "$PROGRAM" || true
  command -v ss >/dev/null 2>&1 && ss -ltnp | grep ":$APP_PORT" || true
  nginx -t || true
  curl -I --max-time 15 "http://$DOMAIN" || true
  curl -I --max-time 15 "https://$DOMAIN" || true
fi

cat <<EOF

============================================================
Installation workflow completed.
Domain       : $DOMAIN
Application  : $APP_DLL
Supervisor   : $PROGRAM
Nginx config : $NGINX_SITE
Logs         : $LOG_DIR
============================================================
EOF
