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

BASE_URL="https://downloads.awkh.art/network"
NAME=""
ACCESS_CODE="${AWKH_ACCESS_CODE:-}"
WG_PORT=51820
H2_PORT=8443
API_PORT=9443
PUBLIC_HOST=""

usage(){
  cat <<EOF
AWKH Network Server installer
Usage: sudo bash install.sh [options]
  --name NAME
  --access-code CODE
  --public-host IP_OR_DOMAIN
  --wg-port PORT
  --h2-port PORT
  --api-port PORT
EOF
}

while [ $# -gt 0 ]; do
  case "$1" in
    --name) NAME="${2:-}"; shift 2;;
    --access-code) ACCESS_CODE="${2:-}"; shift 2;;
    --public-host) PUBLIC_HOST="${2:-}"; shift 2;;
    --wg-port) WG_PORT="${2:-}"; shift 2;;
    --h2-port) H2_PORT="${2:-}"; shift 2;;
    --api-port) API_PORT="${2:-}"; shift 2;;
    -h|--help) usage; exit 0;;
    *) echo "Unknown option: $1" >&2; usage; exit 2;;
  esac
done

[ "$(id -u)" -eq 0 ] || { echo "Run with sudo/root."; exit 1; }
if [ -z "$ACCESS_CODE" ]; then ACCESS_CODE="$(printf '6%.0s' 1 2 3 4 5 6)"; fi

ARCH="$(uname -m)"
case "$ARCH" in
  x86_64|amd64) ARCH=amd64;;
  aarch64|arm64) ARCH=arm64;;
  *) echo "Unsupported architecture: $ARCH"; exit 1;;
esac

if command -v apt-get >/dev/null 2>&1; then
  apt-get update -qq
  DEBIAN_FRONTEND=noninteractive apt-get install -y -qq wireguard-tools iproute2 iptables ca-certificates curl openssl python3
elif command -v dnf >/dev/null 2>&1; then
  dnf install -y wireguard-tools iproute iptables ca-certificates curl openssl python3
elif command -v yum >/dev/null 2>&1; then
  yum install -y wireguard-tools iproute iptables ca-certificates curl openssl python3
else
  echo "Unsupported package manager. Supported: apt, dnf, yum."; exit 1
fi

WAN_IF="$(ip -4 route show default | awk 'NR==1{print $5}')"
[ -n "$WAN_IF" ] || { echo "Cannot detect WAN interface."; exit 1; }
if [ -z "$PUBLIC_HOST" ]; then
  PUBLIC_HOST="$(curl -4 -fsS --connect-timeout 5 --max-time 10 https://api.ipify.org || true)"
fi
[ -n "$PUBLIC_HOST" ] || PUBLIC_HOST="$(hostname -I | awk '{print $1}')"
[ -n "$NAME" ] || NAME="$(hostname)"

ROOT=/opt/awkh-network-server
mkdir -p "$ROOT"/{bin,config,data,certs} /etc/wireguard
chmod 700 "$ROOT/config" "$ROOT/data" "$ROOT/certs"

curl -fsSL "$BASE_URL/server/network_api.py" -o "$ROOT/network_api.py"
chmod 755 "$ROOT/network_api.py"
curl -fsSL "$BASE_URL/server/bin/hysteria-linux-$ARCH" -o "$ROOT/bin/hysteria"
chmod 755 "$ROOT/bin/hysteria"

if [ ! -s "$ROOT/config/wg.key" ]; then
  wg genkey >"$ROOT/config/wg.key"
  chmod 600 "$ROOT/config/wg.key"
fi
WG_PRIV="$(cat "$ROOT/config/wg.key")"
H2_SECRET="$(openssl rand -base64 32 | tr -d '\n')"
ACCESS_HASH="$(printf '%s' "$ACCESS_CODE" | sha256sum | awk '{print $1}')"
SERVER_ID="$(cat "$ROOT/data/server-id" 2>/dev/null || cat /proc/sys/kernel/random/uuid)"
printf '%s\n' "$SERVER_ID" >"$ROOT/data/server-id"

cat >/etc/wireguard/awkh0.conf <<EOF
[Interface]
Address = 10.77.0.1/24
ListenPort = $WG_PORT
PrivateKey = $WG_PRIV
MTU = 1420
PostUp = iptables -A FORWARD -i awkh0 -j ACCEPT; iptables -A FORWARD -o awkh0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -A POSTROUTING -s 10.77.0.0/24 -o $WAN_IF -j MASQUERADE
PostDown = iptables -D FORWARD -i awkh0 -j ACCEPT; iptables -D FORWARD -o awkh0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT; iptables -t nat -D POSTROUTING -s 10.77.0.0/24 -o $WAN_IF -j MASQUERADE
EOF
chmod 600 /etc/wireguard/awkh0.conf

cat >/etc/sysctl.d/99-awkh-network.conf <<EOF
net.ipv4.ip_forward=1
EOF
sysctl --system >/dev/null

SAN="DNS:$PUBLIC_HOST"
if [[ "$PUBLIC_HOST" =~ ^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+$ ]]; then SAN="IP:$PUBLIC_HOST"; fi
openssl req -x509 -newkey rsa:2048 -nodes -days 825 -subj "/CN=$PUBLIC_HOST" -addext "subjectAltName=$SAN" \
  -keyout "$ROOT/certs/server.key" -out "$ROOT/certs/server.crt" >/dev/null 2>&1
chmod 600 "$ROOT/certs/server.key"

cat >"$ROOT/config/hysteria.yaml" <<EOF
listen: 0.0.0.0:$H2_PORT
tls:
  cert: $ROOT/certs/server.crt
  key: $ROOT/certs/server.key
auth:
  type: password
  password: $H2_SECRET
speedTest: true
congestion:
  type: bbr
masquerade:
  type: string
  string:
    content: "AWKH Network"
    statusCode: 200
EOF
chmod 600 "$ROOT/config/hysteria.yaml"

cat >"$ROOT/config/server.json" <<EOF
{
  "server_id":"$SERVER_ID",
  "name":"$NAME",
  "access_code_sha256":"$ACCESS_HASH",
  "public_host":"$PUBLIC_HOST",
  "egress_ip":"$PUBLIC_HOST",
  "api_port":$API_PORT,
  "wg_interface":"awkh0",
  "wg_config":"/etc/wireguard/awkh0.conf",
  "wg_port":$WG_PORT,
  "client_prefix":"10.77.0.",
  "h2_port":$H2_PORT,
  "h2_config":"$ROOT/config/hysteria.yaml",
  "h2_sni":"$PUBLIC_HOST",
  "h2_insecure":true
}
EOF
chmod 600 "$ROOT/config/server.json"
[ -s "$ROOT/data/clients.json" ] || echo '{}' >"$ROOT/data/clients.json"
chmod 600 "$ROOT/data/clients.json"

cp "$ROOT/certs/server.crt" "$ROOT/certs/api.crt"
cp "$ROOT/certs/server.key" "$ROOT/certs/api.key"
chmod 600 "$ROOT/certs/api.key"

cat >/etc/systemd/system/awkh-network-hysteria2.service <<EOF
[Unit]
Description=AWKH Network Hysteria2 server
After=network-online.target
Wants=network-online.target
[Service]
Type=simple
ExecStart=$ROOT/bin/hysteria -c $ROOT/config/hysteria.yaml server --disable-update-check
Restart=on-failure
RestartSec=3
LimitNOFILE=65536
[Install]
WantedBy=multi-user.target
EOF

cat >/etc/systemd/system/awkh-network-api.service <<EOF
[Unit]
Description=AWKH Network enrollment API
After=network-online.target wg-quick@awkh0.service
Wants=network-online.target
[Service]
Type=simple
ExecStart=/usr/bin/python3 $ROOT/network_api.py
Restart=on-failure
RestartSec=2
User=root
NoNewPrivileges=yes
PrivateTmp=yes
ProtectHome=yes
ProtectSystem=strict
ReadWritePaths=$ROOT/data /etc/wireguard
CapabilityBoundingSet=CAP_NET_ADMIN
AmbientCapabilities=CAP_NET_ADMIN
[Install]
WantedBy=multi-user.target
EOF

systemctl daemon-reload
systemctl enable --now wg-quick@awkh0.service awkh-network-hysteria2.service awkh-network-api.service

if command -v ufw >/dev/null 2>&1 && ufw status | grep -q '^Status: active'; then
  ufw allow "$WG_PORT/udp" >/dev/null
  ufw allow "$H2_PORT/udp" >/dev/null
  ufw allow "$API_PORT/tcp" >/dev/null
fi

sleep 2
curl -kfsS "https://127.0.0.1:$API_PORT/health" >/dev/null
systemctl is-active --quiet wg-quick@awkh0.service
systemctl is-active --quiet awkh-network-hysteria2.service
systemctl is-active --quiet awkh-network-api.service

echo
echo "AWKH Network Server ready"
echo "Name: $NAME"
echo "Server: $PUBLIC_HOST"
echo "API: TCP/$API_PORT"
echo "WireGuard: UDP/$WG_PORT"
echo "Hysteria2: UDP/$H2_PORT"
echo "Access code configured."
echo "Cloud firewall/security-group must allow these three ports."
