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

# ============================================================
# Debian 13 VPS Initial Setup Script
#
# Includes:
#  1. Base update + useful tools
#  2. Chrony time sync
#  3. Fail2ban
#  4. Automatic security updates
#  5. Kernel/network tuning
#  6. Journald log limits
#  7. Locale
#  8. Reboot-required check
# ============================================================

export DEBIAN_FRONTEND=noninteractive

# -----------------------------
# Config
# -----------------------------

TIMEZONE="UTC"

# Change this if you prefer en_AU.UTF-8 or en_NZ.UTF-8
LOCALE_NAME="en_US.UTF-8"

# Journald limits
JOURNAL_SYSTEM_MAX_USE="500M"
JOURNAL_RUNTIME_MAX_USE="100M"
JOURNAL_MAX_RETENTION="1month"

# Fail2ban SSH settings
FAIL2BAN_MAXRETRY="5"
FAIL2BAN_FINDTIME="10m"
FAIL2BAN_BANTIME="1h"

# -----------------------------
# Helpers
# -----------------------------

log() {
  echo
  echo "============================================================"
  echo "$1"
  echo "============================================================"
}

warn() {
  echo
  echo "WARNING: $1"
}

require_root() {
  if [ "$(id -u)" -ne 0 ]; then
    echo "This script must be run as root."
    exit 1
  fi
}

detect_debian() {
  if [ ! -f /etc/os-release ]; then
    warn "Cannot detect OS because /etc/os-release is missing."
    return
  fi

  . /etc/os-release

  echo "Detected OS: ${PRETTY_NAME:-unknown}"

  if [ "${ID:-}" != "debian" ]; then
    warn "This script is intended for Debian. Continuing anyway."
  fi

  if [ "${VERSION_ID:-}" != "13" ]; then
    warn "This script is intended for Debian 13. Detected VERSION_ID=${VERSION_ID:-unknown}. Continuing anyway."
  fi
}

safe_systemctl_enable_now() {
  local service="$1"

  if systemctl list-unit-files "$service" >/dev/null 2>&1; then
    systemctl enable --now "$service"
  else
    warn "Service $service not found, skipping enable/start."
  fi
}

# -----------------------------
# Start
# -----------------------------

require_root
detect_debian

log "Step 1/8: Updating APT package lists and upgrading system"

apt-get update
apt-get upgrade -y

log "Step 1/8: Installing base useful packages"

apt-get install -y \
  apt-transport-https \
  bash-completion \
  btop \
  ca-certificates \
  curl \
  dnsutils \
  git \
  gnupg \
  htop \
  iftop \
  iotop \
  iproute2 \
  jq \
  less \
  lsb-release \
  lsof \
  nano \
  ncdu \
  net-tools \
  openssh-client \
  openssh-server \
  rsync \
  screen \
  strace \
  sudo \
  tar \
  tcpdump \
  tmux \
  tree \
  unzip \
  vim \
  wget \
  zip

log "Step 2/8: Installing and enabling Chrony time sync"

apt-get install -y chrony

timedatectl set-timezone "$TIMEZONE" || warn "Could not set timezone to $TIMEZONE"

safe_systemctl_enable_now chrony.service

echo
echo "Current time status:"
timedatectl || true

log "Step 3/8: Installing and configuring Fail2ban"

apt-get install -y fail2ban

mkdir -p /etc/fail2ban/jail.d

cat >/etc/fail2ban/jail.d/sshd.local <<EOF
[sshd]
enabled = true
port = ssh
filter = sshd
backend = systemd
maxretry = ${FAIL2BAN_MAXRETRY}
findtime = ${FAIL2BAN_FINDTIME}
bantime = ${FAIL2BAN_BANTIME}
EOF

safe_systemctl_enable_now fail2ban.service

systemctl restart fail2ban || warn "Could not restart fail2ban."

echo
echo "Fail2ban SSH jail status:"
fail2ban-client status sshd || true

log "Step 4/8: Installing and configuring automatic security updates"

apt-get install -y unattended-upgrades apt-listchanges needrestart

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

cat >/etc/apt/apt.conf.d/51unattended-upgrades-local <<'EOF'
Unattended-Upgrade::Origins-Pattern {
        "origin=Debian,codename=${distro_codename}-security,label=Debian-Security";
        "origin=Debian,codename=${distro_codename},label=Debian";
};

Unattended-Upgrade::Package-Blacklist {
};

Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-New-Unused-Dependencies "true";
Unattended-Upgrade::Remove-Unused-Dependencies "false";

Unattended-Upgrade::Automatic-Reboot "false";
Unattended-Upgrade::SyslogEnable "true";
EOF

systemctl restart unattended-upgrades || true
safe_systemctl_enable_now unattended-upgrades.service

echo
echo "Testing unattended-upgrades config:"
unattended-upgrade --dry-run --debug || warn "unattended-upgrades dry run returned a warning/error. Review output above."

log "Step 5/8: Applying kernel and network tuning"

cat >/etc/sysctl.d/99-vps-tuning.conf <<'EOF'
# ============================================================
# VPS kernel/network tuning
# ============================================================

# Use fair queueing. Recommended with BBR.
net.core.default_qdisc = fq

# Enable BBR congestion control.
net.ipv4.tcp_congestion_control = bbr

# Enable TCP Fast Open.
net.ipv4.tcp_fastopen = 3

# Do not act as a router by default.
net.ipv4.ip_forward = 0
net.ipv6.conf.all.forwarding = 0

# Basic anti-spoofing / safer IPv4 behaviour.
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.ipv4.conf.default.accept_redirects = 0
net.ipv6.conf.all.accept_redirects = 0
net.ipv6.conf.default.accept_redirects = 0

# Do not send ICMP redirects.
net.ipv4.conf.all.send_redirects = 0
net.ipv4.conf.default.send_redirects = 0

# Ignore source-routed packets.
net.ipv4.conf.all.accept_source_route = 0
net.ipv4.conf.default.accept_source_route = 0
net.ipv6.conf.all.accept_source_route = 0
net.ipv6.conf.default.accept_source_route = 0

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

# Reasonable file handle limit.
fs.file-max = 2097152

# Reasonable memory behaviour for small VPSes.
vm.swappiness = 10
vm.vfs_cache_pressure = 50
EOF

sysctl --system

echo
echo "Current TCP congestion control:"
sysctl net.ipv4.tcp_congestion_control || true

echo
echo "Available TCP congestion controls:"
sysctl net.ipv4.tcp_available_congestion_control || true

log "Step 6/8: Setting journald log size limits"

mkdir -p /etc/systemd/journald.conf.d

cat >/etc/systemd/journald.conf.d/99-vps-limits.conf <<EOF
[Journal]
SystemMaxUse=${JOURNAL_SYSTEM_MAX_USE}
RuntimeMaxUse=${JOURNAL_RUNTIME_MAX_USE}
MaxRetentionSec=${JOURNAL_MAX_RETENTION}
Compress=yes
EOF

systemctl restart systemd-journald

echo
echo "Current journal disk usage:"
journalctl --disk-usage || true

log "Step 7/8: Configuring locale"

apt-get install -y locales

if grep -q "^# *${LOCALE_NAME} UTF-8" /etc/locale.gen; then
  sed -i "s/^# *${LOCALE_NAME} UTF-8/${LOCALE_NAME} UTF-8/" /etc/locale.gen
elif ! grep -q "^${LOCALE_NAME} UTF-8" /etc/locale.gen; then
  echo "${LOCALE_NAME} UTF-8" >> /etc/locale.gen
fi

locale-gen
update-locale LANG="$LOCALE_NAME"

echo
echo "Configured locale:"
localectl status || true

log "Cleaning up packages"

apt-get autoremove -y
apt-get autoclean -y

log "Step 8/8: Reboot-required check"

REBOOT_REQUIRED="no"

if [ -f /var/run/reboot-required ]; then
  REBOOT_REQUIRED="yes"
fi

if command -v needrestart >/dev/null 2>&1; then
  echo
  echo "needrestart summary:"
  needrestart -b || true
fi

echo
echo "============================================================"
echo "Debian 13 VPS initial setup complete."
echo "============================================================"
echo "Timezone: $TIMEZONE"
echo "Locale:   $LOCALE_NAME"
echo "Reboot required: $REBOOT_REQUIRED"
echo

if [ "$REBOOT_REQUIRED" = "yes" ]; then
  echo "A reboot is recommended:"
  echo "  reboot"
else
  echo "No reboot-required flag detected."
fi

echo
echo "Useful checks:"
echo "  systemctl status chrony"
echo "  systemctl status fail2ban"
echo "  fail2ban-client status sshd"
echo "  systemctl status unattended-upgrades"
echo "  journalctl --disk-usage"
echo "  sysctl net.ipv4.tcp_congestion_control"
echo