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

if [[ $EUID -ne 0 ]]; then
  echo "This script must be run as root (use sudo)." >&2
  exit 1
fi

APP_USER="${APP_USER:-myroadtrip}"
APP_HOME="${APP_HOME:-/srv/myroadtrip}"
APEX_DOMAIN="${APEX_DOMAIN:-roadtripper.io}"
NODE_MAJOR="${NODE_MAJOR:-20}"
OSRM_PORT="${OSRM_PORT:-5000}"
TILES_PORT="${TILES_PORT:-8080}"
EXPOSE_MAP_PORTS="${EXPOSE_MAP_PORTS:-false}"
REDIS_PASSWORD_FILE="${REDIS_PASSWORD_FILE:-/etc/redis/.redis_pass}"
RESET_REDIS_CONF="${RESET_REDIS_CONF:-false}"

# Redis password strategy:
# - Reuse existing file if present
# - Allow overriding via REDIS_PASSWORD env (for manual rotation)
# - Generate once on first run (40 hex chars), then persist
EXISTING_REDIS_PASS=""
if [[ -f "$REDIS_PASSWORD_FILE" ]]; then
  EXISTING_REDIS_PASS="$(cat "$REDIS_PASSWORD_FILE" 2>/dev/null || true)"
fi

if [[ -n "${REDIS_PASSWORD:-}" ]]; then
  FINAL_REDIS_PASS="$REDIS_PASSWORD"
elif [[ -n "$EXISTING_REDIS_PASS" ]]; then
  FINAL_REDIS_PASS="$EXISTING_REDIS_PASS"
else
  FINAL_REDIS_PASS="$(openssl rand -hex 40)"
fi

REDIS_PASSWORD="$FINAL_REDIS_PASS"

echo ">>> Updating base system and installing core packages..."
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get -y full-upgrade
apt-get install -y --no-install-recommends \
  build-essential git curl unzip rsync jq ca-certificates gnupg lsb-release software-properties-common \
  ufw fail2ban unattended-upgrades logrotate net-tools htop tmux ripgrep \
  redis-server docker.io docker-compose-plugin caddy \
  python3 python3-pip \
  aide aide-common \
  rkhunter chkrootkit \
  psad clamav clamav-daemon \
  apparmor apparmor-utils \
  auditd \
  prometheus-node-exporter \
  sysstat iotop iftop dstat \
  zram-tools \
  chrony \
  zstd bc

timedatectl set-timezone UTC
timedatectl set-ntp true
echo ">>> Enabling services..."
for service in unattended-upgrades docker redis-server chrony prometheus-node-exporter sysstat; do
  echo "--- Configuring $service ---"
  systemctl enable "$service" || echo "WARNING: Failed to enable $service"
  # Try to start, but don't hang forever
  timeout 10s systemctl restart "$service" || echo "WARNING: Failed to start $service (or timed out)"
done

echo ">>> Setting up DNS caching for faster external queries..."
apt-get install -y dnsmasq
cat >/etc/dnsmasq.d/cache.conf <<'EOF'
# DNS cache config
cache-size=10000
no-negcache
local-ttl=300
EOF

# Ensure dnsmasq owns port 53 (disable systemd-resolved and point resolv.conf to localhost)
systemctl stop systemd-resolved || true
systemctl disable systemd-resolved || true
rm -f /etc/resolv.conf
cat >/etc/resolv.conf <<'EOF'
nameserver 127.0.0.1
nameserver 1.1.1.1
nameserver 1.0.0.1
nameserver 8.8.8.8
EOF

# Upstream resolvers
cat >/etc/dnsmasq.d/upstream.conf <<'EOF'
no-resolv
listen-address=127.0.0.1
server=1.1.1.1
server=1.0.0.1
EOF

systemctl enable --now dnsmasq || true

echo ">>> Configuring ZRAM (compressed swap in RAM)..."
if command -v zramctl >/dev/null 2>&1; then
  cat >/etc/default/zramswap <<'EOF'
ALLOCATION=50
PRIORITY=100
SIZE=2048
COMP_ALG=zstd
EOF
  systemctl enable zramswap || true
  systemctl restart zramswap || true
fi

echo ">>> Hardening SSH (password auth will be disabled once SSH keys exist)..."
AUTHORIZED_KEYS="/home/ubuntu/.ssh/authorized_keys"
if [[ -f "$AUTHORIZED_KEYS" ]] && [[ -s "$AUTHORIZED_KEYS" ]]; then
  sed -i.bak 's/^\s*#\?\s*PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
  sed -i.bak 's/^\s*#\?\s*PermitRootLogin.*/PermitRootLogin no/' /etc/ssh/sshd_config
  systemctl reload sshd || systemctl restart sshd
  echo "SSH hardened: password auth disabled"
else
  echo "WARNING: $AUTHORIZED_KEYS is empty or doesn't exist. SSH keys required before hardening." >&2
fi

echo ">>> Creating application user ($APP_USER)..."
if ! id -u "$APP_USER" >/dev/null 2>&1; then
  adduser --disabled-password --gecos "" "$APP_USER"
fi
usermod -aG docker "$APP_USER"
install -d -o "$APP_USER" -g "$APP_USER" "$APP_HOME"

echo ">>> Configuring UFW firewall with rate limiting..."
ufw --force reset
ufw default deny incoming
ufw default allow outgoing
ufw logging on

# SSH with rate limiting (max 6 connections per 30s per IP)
ufw limit 22/tcp comment 'SSH - rate limited'

# HTTP/HTTPS
ufw allow 80/tcp comment 'HTTP'
ufw allow 443/tcp comment 'HTTPS'

# Application ports (kept closed by default; set EXPOSE_MAP_PORTS=true to expose)
if [[ "$EXPOSE_MAP_PORTS" == "true" ]]; then
  ufw allow "${OSRM_PORT}/tcp" comment 'OSRM HTTP'
  ufw allow "${TILES_PORT}/tcp" comment 'Tile server HTTP'
fi

# Block common attack ports
ufw deny 23/tcp comment 'Block Telnet'
ufw deny 135/tcp comment 'Block RPC'
ufw deny 139/tcp comment 'Block NetBIOS'
ufw deny 445/tcp comment 'Block SMB'
ufw deny 3306/tcp comment 'Block MySQL'
ufw deny 5432/tcp comment 'Block PostgreSQL'
ufw deny 6379/tcp comment 'Block Redis external'
ufw deny 27017/tcp comment 'Block MongoDB'

ufw --force enable

echo ">>> Configuring Fail2ban with advanced protection..."
install -d /etc/fail2ban/jail.d
install -d /etc/fail2ban/filter.d

# SSH protection (aggressive)
cat >/etc/fail2ban/jail.d/sshd.local <<'EOF'
[sshd]
enabled = true
mode = aggressive
maxretry = 3
findtime = 10m
bantime = 24h
EOF

# Caddy 4xx protection
cat >/etc/fail2ban/filter.d/caddy-4xx.conf <<'EOF'
[Definition]
failregex = ^<HOST> .+ "(GET|POST|HEAD|PUT|DELETE|OPTIONS) .+" 4\d\d .*
ignoreregex =
EOF

cat >/etc/fail2ban/jail.d/caddy.local <<'EOF'
[caddy-4xx]
enabled = true
filter = caddy-4xx
logpath = /var/log/caddy/*.log
maxretry = 10
findtime = 10m
bantime = 12h
EOF

# DDoS protection - limit repeated requests
cat >/etc/fail2ban/filter.d/caddy-ddos.conf <<'EOF'
[Definition]
failregex = ^<HOST> .+
ignoreregex =
EOF

cat >/etc/fail2ban/jail.d/caddy-ddos.local <<'EOF'
[caddy-ddos]
enabled = true
filter = caddy-ddos
logpath = /var/log/caddy/*.log
maxretry = 100
findtime = 60
bantime = 1h
EOF

# Recidive jail - ban persistent offenders
cat >/etc/fail2ban/jail.d/recidive.local <<'EOF'
[recidive]
enabled = true
logpath = /var/log/fail2ban.log
bantime = 1w
findtime = 1d
maxretry = 3
EOF

if id caddy >/dev/null 2>&1; then
  install -d -o caddy -g caddy /var/log/caddy
  touch /var/log/caddy/access.log
  chown caddy:caddy /var/log/caddy/access.log
  chmod 640 /var/log/caddy/access.log
else
  install -d /var/log/caddy
  touch /var/log/caddy/access.log
  chmod 644 /var/log/caddy/access.log
fi
systemctl enable fail2ban || true
systemctl restart fail2ban || true

echo ">>> Installing Node.js ${NODE_MAJOR}.x and pnpm..."
NODE_OK=false
if command -v node >/dev/null 2>&1; then
  NODE_CURR_MAJOR="$(node -p "process.versions.node.split('.')[0]" 2>/dev/null || echo "")"
  if [[ "$NODE_CURR_MAJOR" == "$NODE_MAJOR" ]]; then
    echo "Node.js ${NODE_MAJOR}.x already present; skipping install."
    NODE_OK=true
  fi
fi

if [[ "$NODE_OK" != "true" ]]; then
  mkdir -p /etc/apt/keyrings
  rm -f /etc/apt/keyrings/nodesource.gpg /tmp/nodesource.gpg
  if ! curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /tmp/nodesource.gpg; then
    echo "WARNING: DNS/key fetch failed for deb.nodesource.com, retrying with fallback resolvers..."
    cat >/etc/resolv.conf <<'EOF'
nameserver 1.1.1.1
nameserver 1.0.0.1
nameserver 8.8.8.8
EOF
    systemctl restart dnsmasq || true
    curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /tmp/nodesource.gpg
  fi
  install -m 644 /tmp/nodesource.gpg /etc/apt/keyrings/nodesource.gpg
  rm -f /tmp/nodesource.gpg
  echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" > /etc/apt/sources.list.d/nodesource.list
  if ! apt-get update; then
    echo "WARNING: apt-get update failed for NodeSource; falling back to existing node (if any)." >&2
  else
    apt-get install -y nodejs
  fi
fi

corepack enable
corepack prepare pnpm@9.15.9 --activate

echo ">>> Preparing application directories..."
install -d -o "$APP_USER" -g "$APP_USER" "$APP_HOME"/{current,releases,shared}
install -d -o "$APP_USER" -g "$APP_USER" "$APP_HOME/repo"
install -d -o "$APP_USER" -g "$APP_USER" /srv/osrm
install -d -o "$APP_USER" -g "$APP_USER" /srv/tiles
install -d -o "$APP_USER" -g "$APP_USER" /srv/www/roadtripper
install -d -o "$APP_USER" -g "$APP_USER" /var/log/myroadtrip

echo ">>> Securing Redis (local-only + auth + systemd supervision)..."
# (Re)seed redis.conf if missing or RESET_REDIS_CONF=true
if [[ "$RESET_REDIS_CONF" == "true" || ! -s /etc/redis/redis.conf ]]; then
  if [[ -f /usr/share/doc/redis-server/examples/redis.conf.gz ]]; then
    zcat /usr/share/doc/redis-server/examples/redis.conf.gz > /etc/redis/redis.conf
  elif [[ -f /usr/share/doc/redis-server/redis.conf ]]; then
    cp /usr/share/doc/redis-server/redis.conf /etc/redis/redis.conf
  else
    echo "WARNING: No Redis template found; keeping existing /etc/redis/redis.conf" >&2
  fi
fi

# Bind loopback only
sed -i 's/^#\?\s*bind .*/bind 127.0.0.1 ::1/' /etc/redis/redis.conf
sed -i 's/^#\?\s*protected-mode .*/protected-mode yes/' /etc/redis/redis.conf
sed -i 's/^#\?\s*supervised .*/supervised systemd/' /etc/redis/redis.conf

# Generate/store password (write only if missing or rotated)
umask 027
if [[ ! -f "$REDIS_PASSWORD_FILE" ]] || ! grep -q "$REDIS_PASSWORD" "$REDIS_PASSWORD_FILE"; then
  echo "$REDIS_PASSWORD" > "$REDIS_PASSWORD_FILE"
  chown redis:redis "$REDIS_PASSWORD_FILE"
  chmod 640 "$REDIS_PASSWORD_FILE"
fi

# Enforce password and hide dangerous commands (idempotent)
if grep -q '^requirepass ' /etc/redis/redis.conf; then
  sed -i "s/^requirepass .*/requirepass $REDIS_PASSWORD/" /etc/redis/redis.conf
else
  printf "\n# myroadtrip security\nrequirepass %s\n" "$REDIS_PASSWORD" >> /etc/redis/redis.conf
fi

for cmd in FLUSHALL FLUSHDB CONFIG SHUTDOWN; do
  if ! grep -q "^rename-command $cmd \"\"" /etc/redis/redis.conf; then
    printf "rename-command %s \"\"\n" "$cmd" >> /etc/redis/redis.conf
  fi
done

echo "Restarting Redis with new configuration..."
timeout 15s systemctl restart redis-server || echo "WARNING: Redis restart failed or timed out (continuing anyway)" >&2
# Sanity check Redis readiness (ignores failure to avoid hard stop)
if command -v redis-cli >/dev/null 2>&1; then
  if [[ -n "$REDIS_PASSWORD" ]]; then
    redis-cli -a "$REDIS_PASSWORD" PING >/dev/null 2>&1 || echo "WARNING: redis-cli ping with password failed" >&2
  else
    redis-cli PING >/dev/null 2>&1 || echo "WARNING: redis-cli ping failed" >&2
  fi
else
  echo "WARNING: redis-cli not found; skipping Redis readiness check" >&2
fi

echo ">>> Configuring kernel security (sysctl hardening)..."
cat >/etc/sysctl.d/99-security.conf <<'EOF'
# IP Forwarding
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

# SYN flood protection
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_synack_retries = 2
net.ipv4.tcp_syn_retries = 5

# IP spoofing protection
net.ipv4.conf.all.rp_filter = 1
net.ipv4.conf.default.rp_filter = 1

# Ignore ICMP redirects
net.ipv4.conf.all.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv4.conf.all.send_redirects = 0

# Ignore ICMP ping requests (optional - uncomment to enable)
# net.ipv4.icmp_echo_ignore_all = 1

# Log suspicious packets
net.ipv4.conf.all.log_martians = 1

# Ignore broadcast pings
net.ipv4.icmp_echo_ignore_broadcasts = 1

# Ignore bogus ICMP error responses
net.ipv4.icmp_ignore_bogus_error_responses = 1

# TCP hardening
net.ipv4.tcp_timestamps = 0
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_keepalive_time = 300
net.ipv4.tcp_keepalive_probes = 5
net.ipv4.tcp_keepalive_intvl = 15

# Disable source packet routing
net.ipv4.conf.all.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0

# Memory protection
kernel.randomize_va_space = 2
kernel.kptr_restrict = 2
kernel.yama.ptrace_scope = 1
EOF

sysctl -p /etc/sysctl.d/99-security.conf

echo ">>> Optimizing system performance..."
cat >/etc/sysctl.d/99-performance.conf <<'EOF'
# Network performance
net.core.somaxconn = 8192
net.core.netdev_max_backlog = 10000
net.ipv4.tcp_max_syn_backlog = 8192
net.ipv4.tcp_slow_start_after_idle = 0
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_fin_timeout = 15
net.ipv4.tcp_fastopen = 3

# TCP buffer optimization
net.core.rmem_max = 134217728
net.core.wmem_max = 134217728
net.core.rmem_default = 16777216
net.core.wmem_default = 16777216
net.ipv4.tcp_rmem = 4096 87380 134217728
net.ipv4.tcp_wmem = 4096 87380 134217728
net.ipv4.udp_rmem_min = 16384
net.ipv4.udp_wmem_min = 16384

# Increase connection tracking
net.netfilter.nf_conntrack_max = 524288
net.netfilter.nf_conntrack_tcp_timeout_established = 432000
net.netfilter.nf_conntrack_tcp_timeout_time_wait = 30

# File system optimization
fs.file-max = 4194304
fs.nr_open = 4194304
fs.aio-max-nr = 1048576
vm.swappiness = 1
vm.dirty_ratio = 10
vm.dirty_background_ratio = 3
vm.vfs_cache_pressure = 50
vm.min_free_kbytes = 262144

# BBR congestion control (faster TCP)
net.core.default_qdisc = fq
net.ipv4.tcp_congestion_control = bbr

# Memory optimization
vm.overcommit_memory = 1
vm.panic_on_oom = 0
EOF

sysctl -p /etc/sysctl.d/99-performance.conf

echo ">>> Configuring Redis performance..."
cat >>/etc/redis/redis.conf <<'EOF'

# Performance optimization
maxmemory 2gb
maxmemory-policy allkeys-lru
save ""
appendonly no
tcp-backlog 2048
timeout 300
tcp-keepalive 60
maxclients 20000

# Memory optimizations
activedefrag yes
activedefrag-ignore-bytes 100mb
activedefrag-threshold-lower 10
activedefrag-cycle-min 5
activedefrag-cycle-max 75

# I/O threads (utilize multiple cores)
io-threads 4
io-threads-do-reads yes

# Network optimization
tcp-nodelay yes

# Lazy freeing
lazyfree-lazy-eviction yes
lazyfree-lazy-expire yes
lazyfree-lazy-server-del yes
replica-lazy-flush yes
EOF

systemctl restart redis-server

echo ">>> Configuring process limits..."
cat >/etc/security/limits.d/99-myroadtrip.conf <<EOF
$APP_USER soft nofile 65535
$APP_USER hard nofile 65535
$APP_USER soft nproc 4096
$APP_USER hard nproc 4096
root soft nofile 65535
root hard nofile 65535
* soft nofile 65535
* hard nofile 65535
EOF

echo ">>> Setting up intrusion detection (PSAD)..."
if command -v psad >/dev/null 2>&1; then
  cat >/etc/psad/psad.conf <<EOF
EMAIL_ADDRESSES admin@${APEX_DOMAIN};
HOSTNAME $(hostname);
ENABLE_AUTO_IDS Y;
ENABLE_AUTO_IDS_EMAILS Y;
MIN_DANGER_LEVEL 1;
EOF

  psad --sig-update || echo "WARNING: PSAD sig-update failed"
  psad -R || echo "WARNING: PSAD restart failed"
  systemctl enable psad || true
  systemctl restart psad || true
else
  echo "WARNING: PSAD not installed, skipping configuration"
fi

echo ">>> Configuring ClamAV antivirus..."
if command -v freshclam >/dev/null 2>&1; then
  systemctl stop clamav-freshclam || true
  freshclam || echo "WARNING: freshclam update failed"
  systemctl enable clamav-freshclam || true
  systemctl start clamav-freshclam || true
  systemctl enable clamav-daemon || true
  systemctl start clamav-daemon || true

  # Daily scan script
  install -d /var/log/clamav
  cat >/etc/cron.daily/clamav-scan <<'EOF'
#!/bin/bash
if command -v clamscan >/dev/null 2>&1; then
  SCAN_DIR="/srv/myroadtrip /var/www"
  LOG_FILE="/var/log/clamav/daily-scan.log"
  clamscan -r -i --exclude-dir="^/sys" $SCAN_DIR >> $LOG_FILE 2>&1 || true
fi
EOF
  chmod +x /etc/cron.daily/clamav-scan
else
  echo "WARNING: ClamAV not installed, skipping configuration"
fi

echo ">>> Initializing AIDE (file integrity monitoring)..."
if command -v aideinit >/dev/null 2>&1; then
  aideinit || echo "WARNING: AIDE init failed, skipping..."
  if [[ -f /var/lib/aide/aide.db.new ]]; then
    mv /var/lib/aide/aide.db.new /var/lib/aide/aide.db
  fi
else
  echo "WARNING: AIDE not installed, skipping initialization"
fi

# Weekly AIDE check
cat >/etc/cron.weekly/aide-check <<EOF
#!/bin/bash
if command -v aide >/dev/null 2>&1; then
  REPORT=\$(/usr/bin/aide --check 2>&1 || true)
  if command -v mail >/dev/null 2>&1; then
    printf '%s\n' "\$REPORT" | mail -s "AIDE Report for \$(hostname)" admin@${APEX_DOMAIN} || true
  else
    echo "\$REPORT" >> /var/log/myroadtrip/aide.log
  fi
fi
EOF
chmod +x /etc/cron.weekly/aide-check

echo ">>> Setting up automatic security updates..."
cat >/etc/apt/apt.conf.d/50unattended-upgrades <<'EOF'
Unattended-Upgrade::Allowed-Origins {
    "${distro_id}:${distro_codename}";
    "${distro_id}:${distro_codename}-security";
    "${distro_id}ESMApps:${distro_codename}-apps-security";
    "${distro_id}ESM:${distro_codename}-infra-security";
};
Unattended-Upgrade::AutoFixInterruptedDpkg "true";
Unattended-Upgrade::MinimalSteps "true";
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";
Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::Automatic-Reboot-WithUsers "false";
Unattended-Upgrade::Automatic-Reboot-Time "03:00";
Unattended-Upgrade::Mail "admin@${APEX_DOMAIN}";
Unattended-Upgrade::MailReport "only-on-error";
EOF

cat >/etc/apt/apt.conf.d/20auto-upgrades <<'EOF'
APT::Periodic::Update-Package-Lists "1";
APT::Periodic::Download-Upgradeable-Packages "1";
APT::Periodic::AutocleanInterval "7";
APT::Periodic::Unattended-Upgrade "1";
EOF

systemctl enable unattended-upgrades
systemctl restart unattended-upgrades

echo ">>> Configuring audit daemon (auditd)..."
if command -v auditctl >/dev/null 2>&1; then
  install -d /etc/audit/rules.d
  cat >>/etc/audit/rules.d/audit.rules <<'EOF'
# Monitor authentication attempts
-w /var/log/auth.log -p wa -k auth_logs
-w /etc/passwd -p wa -k passwd_changes
-w /etc/shadow -p wa -k shadow_changes
-w /etc/sudoers -p wa -k sudoers_changes

# Monitor network configuration
-w /etc/network/ -p wa -k network_changes

# Monitor systemd services
-w /etc/systemd/ -p wa -k systemd_changes

# Monitor application files
-w /srv/myroadtrip/ -p wa -k app_changes
EOF

  augenrules --load || echo "WARNING: augenrules failed"
  systemctl enable auditd || true
  systemctl restart auditd || true
else
  echo "WARNING: auditd not installed, skipping configuration"
fi

echo ">>> Updating logrotate configuration..."
cat >/etc/logrotate.d/myroadtrip <<'EOF'
/var/log/myroadtrip/*.log /var/log/caddy/*.log {
  daily
  rotate 14
  missingok
  notifempty
  compress
  delaycompress
  compresscmd /usr/bin/zstd
  compressoptions -19 --rm
  uncompresscmd /usr/bin/unzstd
  compressext .zst
  sharedscripts
  postrotate
    systemctl kill -s HUP caddy >/dev/null 2>&1 || true
  endscript
  size 100M
  maxage 90
}
EOF

echo ">>> Creating systemd service for API..."
cat >/etc/systemd/system/myroadtrip-api.service <<EOF
[Unit]
Description=MyRoadTrip Fastify API
After=network-online.target redis-server.service
Wants=redis-server.service

[Service]
User=$APP_USER
Group=$APP_USER
WorkingDirectory=$APP_HOME/repo/apps/api
Environment=NODE_ENV=production
Environment=NODE_OPTIONS=--max-old-space-size=4096
EnvironmentFile=$APP_HOME/.env.production
ExecStart=/usr/bin/env pnpm start
# Smart restart with exponential backoff
Restart=on-failure
RestartSec=5
StartLimitInterval=200
StartLimitBurst=10
# Kill gracefully with SIGTERM, wait 30s, then SIGKILL
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=30
StandardOutput=append:/var/log/myroadtrip/api.out.log
StandardError=append:/var/log/myroadtrip/api.err.log
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable myroadtrip-api

echo ">>> Creating Caddyfile with security headers and caching..."
cat >/etc/caddy/Caddyfile <<EOF
{
  email admin@${APEX_DOMAIN}
  log {
    output file /var/log/caddy/access.log {
      roll_size 25mb
      roll_keep 7
      roll_keep_for 720h
    }
    format console
    level INFO
  }
  servers { protocols h1 h2 h3 }
}

${APEX_DOMAIN}, www.${APEX_DOMAIN} {
  root * /srv/www/roadtripper
  encode gzip zstd

  @staticAssets {
    path /assets/*
    path *.js *.css *.woff *.woff2 *.ttf *.eot *.svg *.png *.jpg *.jpeg *.webp *.gif *.ico
  }
  header @staticAssets Cache-Control "public, max-age=31536000, immutable"

  @serviceWorkers {
    path /sw.js
    path /workbox-*.js
    path /registerSW.js
    path /service-worker.js
  }
  header @serviceWorkers Cache-Control "no-store"

  @htmlShell {
    path /
    path *.html
  }
  header @htmlShell Cache-Control "no-cache, no-store, must-revalidate"
  header @htmlShell Pragma "no-cache"
  header @htmlShell Expires "0"

  header {
    Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
    X-Content-Type-Options "nosniff"
    X-Frame-Options "DENY"
    Referrer-Policy "strict-origin-when-cross-origin"
    Permissions-Policy "geolocation=(self), microphone=(), camera=()"
    -Server
  }

  try_files {path} /index.html
  
  # HTTP/2 Server Push for critical resources
  @index path /
  header @index Link "</assets/index.css>; rel=preload; as=style, </assets/index.js>; rel=preload; as=script"

  handle_path /api/* {
    reverse_proxy 127.0.0.1:3000 {
      header_up Host api.${APEX_DOMAIN}
      header_up X-Forwarded-For {remote}
      header_up X-Forwarded-Proto {scheme}
    }
  }

  file_server
}

api.${APEX_DOMAIN} {
  encode br gzip zstd
  reverse_proxy 127.0.0.1:3000 {
    header_up Host {http.request.host}
    header_up X-Forwarded-For {remote}
    header_up X-Forwarded-Proto {scheme}
  }
}

osrm.${APEX_DOMAIN} {
  encode gzip zstd
  reverse_proxy 127.0.0.1:5000
}

tiles.${APEX_DOMAIN} {
  encode gzip zstd
  reverse_proxy 127.0.0.1:8080
}
EOF

systemctl reload caddy || echo "WARNING: Caddy reload failed (will work after first config)"

echo ">>> Setting up monitoring and alerting..."
cat >/usr/local/bin/system-health-check <<'EOF'
#!/bin/bash
# Quick system health check
LOAD=$(uptime | awk -F'load average:' '{print $2}' | cut -d, -f1 | xargs)
MEM=$(free | awk '/Mem:/ {printf "%.0f", $3/$2 * 100}')
DISK=$(df -h / | awk 'NR==2 {print $5}' | sed 's/%//')
CPU=$(top -bn1 | grep "Cpu(s)" | awk '{print $2}' | cut -d'%' -f1)

echo "Load: $LOAD | CPU: ${CPU}% | RAM: ${MEM}% | Disk: ${DISK}%"

if (( $(echo "$MEM > 90" | bc -l) )); then
  echo "WARNING: High memory usage" >&2
fi
if (( $(echo "$DISK > 85" | bc -l) )); then
  echo "WARNING: High disk usage" >&2
fi
EOF
chmod +x /usr/local/bin/system-health-check

echo ">>> Setting up systemd drop-in for better service isolation..."
install -d /etc/systemd/system/caddy.service.d
cat >/etc/systemd/system/caddy.service.d/hardening.conf <<'EOF'
[Service]
PrivateTmp=yes
ProtectSystem=strict
ReadWritePaths=/var/log/caddy /var/lib/caddy
NoNewPrivileges=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
EOF

install -d /etc/systemd/system/redis-server.service.d
cat >/etc/systemd/system/redis-server.service.d/limits.conf <<'EOF'
[Service]
LimitNOFILE=65536
LimitNPROC=32768
OOMScoreAdjust=-100
EOF

install -d /etc/systemd/system/myroadtrip-api.service.d
cat >/etc/systemd/system/myroadtrip-api.service.d/hardening.conf <<'EOF'
[Service]
PrivateTmp=yes
ProtectSystem=strict
ReadWritePaths=/var/log/myroadtrip /srv/myroadtrip
NoNewPrivileges=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictNamespaces=true
RestrictRealtime=true
RestrictSUIDSGID=true
LimitNOFILE=65536
OOMScoreAdjust=-200
EOF

systemctl daemon-reload

echo ">>> Creating performance monitoring script..."
cat >/usr/local/bin/perf-report <<'EOF'
#!/bin/bash
echo "=== System Performance Report ==="
echo "Date: $(date)"
echo ""
echo "--- CPU & Load ---"
uptime
mpstat 1 1 2>/dev/null || echo "mpstat not available"
echo ""
echo "--- Memory ---"
free -h
echo ""
echo "--- Disk I/O ---"
iostat -x 1 1 2>/dev/null || echo "iostat not available"
echo ""
echo "--- Network ---"
ss -s
echo ""
echo "--- Top Processes (CPU) ---"
ps aux --sort=-%cpu | head -6
echo ""
echo "--- Top Processes (Memory) ---"
ps aux --sort=-%mem | head -6
echo ""
echo "--- Redis Stats ---"
REDIS_AUTH_ARGS=()
if [[ -f /etc/redis/.redis_pass ]]; then
  REDIS_AUTH_ARGS=(-a "$(cat /etc/redis/.redis_pass)" --no-auth-warning)
fi
redis-cli "${REDIS_AUTH_ARGS[@]}" --stat --interval 1 --count 1 2>/dev/null || echo "Redis not available"
echo ""
echo "--- Service Status ---"
systemctl status myroadtrip-api --no-pager -l 2>/dev/null || true
EOF
chmod +x /usr/local/bin/perf-report

echo ">>> Setting up disk space monitoring..."
cat >/usr/local/bin/check-disk-space <<'EOF'
#!/bin/bash
THRESHOLD=85
USAGE=$(df / | tail -1 | awk '{print $5}' | sed 's/%//')
if [ "$USAGE" -gt "$THRESHOLD" ]; then
  echo "[$(date)] WARNING: Disk usage at ${USAGE}%" | tee -a /var/log/myroadtrip/disk-alerts.log
  # Cleanup old logs if space critical
  if [ "$USAGE" -gt 90 ]; then
    find /var/log -type f -name "*.log.*" -mtime +3 -delete 2>/dev/null || true
    find /srv/myroadtrip/backups -type f -mtime +3 -delete 2>/dev/null || true
  fi
fi
EOF
chmod +x /usr/local/bin/check-disk-space
cat >/etc/cron.hourly/disk-monitor <<'EOF'
#!/bin/bash
/usr/local/bin/check-disk-space
EOF
chmod +x /etc/cron.hourly/disk-monitor

echo ">>> Bootstrap completed."
echo ""
echo "═══════════════════════════════════════════════════════════════"
echo "  🛡️  VPS HARDENING COMPLETE"
echo "═══════════════════════════════════════════════════════════════"
echo ""
echo "✅ Security features enabled:"
echo "   • UFW firewall with rate limiting"
echo "   • Fail2ban (SSH + HTTP + DDoS + Recidive)"
echo "   • Kernel hardening (sysctl)"
echo "   • PSAD intrusion detection"
echo "   • ClamAV antivirus (daily scans)"
echo "   • AIDE file integrity monitoring"
echo "   • Auditd security auditing"
echo "   • AppArmor enabled"
echo "   • Unattended security updates"
echo ""
echo "✅ Services configured:"
echo "   • Redis (localhost only, protected)"
echo "   • Caddy (HTTPS + security headers + rate limiting)"
echo "   • Docker (rootless capable)"
echo "   • Node.js ${NODE_MAJOR}.x + pnpm"
echo ""
echo "⚠️  Next steps:"
echo "  1) Set DNS for ${APEX_DOMAIN} and subdomains (A records to this server IP)"
echo "  2) Copy your production .env.production to $APP_HOME/"
echo "  3) Run the deployment script:"
echo "     ./scripts/vps/deploy_on_vps.sh"
echo "     (This will clone, install deps, build, and start services)"
echo ""
echo "🔒 CRITICAL: Ensure .env.production contains:"
echo "    - All VITE_AUTH0_* variables (DOMAIN, CLIENT_ID, AUDIENCE, SCOPE, ROLES_CLAIM)"
echo "    - Firebase credentials (PROJECT_ID, CLIENT_EMAIL, PRIVATE_KEY)"
echo "    - Redis connection details"
echo ""
echo "📊 Security monitoring:"
echo "    - Fail2ban status: sudo fail2ban-client status"
echo "    - UFW status: sudo ufw status verbose"
echo "    - PSAD status: sudo psad --Status"
echo "    - Audit logs: sudo ausearch -m avc -ts recent"
echo "    - ClamAV logs: /var/log/clamav/daily-scan.log"
echo ""
echo "📚 Documentation:"
echo "    - Auth0 setup: $APP_HOME/repo/docs/AUTH0_API_SETUP.md"
echo "    - Firebase fix: $APP_HOME/repo/docs/FIREBASE_LAZY_LOAD_FIX.md"
echo ""
echo "═══════════════════════════════════════════════════════════════"
