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

EDGE_FQDN="${EDGE_FQDN:-}"
ORIGIN_FQDN="${ORIGIN_FQDN:-ix.x2chat.com}"
ADMIN_EMAIL="${ADMIN_EMAIL:-}"
EDGE_NAME="${EDGE_NAME:-edge-r1}"
SSH_ADMIN_IP="${SSH_ADMIN_IP:-}"

if [[ -z "${EDGE_FQDN}" || -z "${ADMIN_EMAIL}" ]]; then
  cat <<'USAGE'
Usage:
  EDGE_FQDN=api-r1.example.com ADMIN_EMAIL=admin@example.com [ORIGIN_FQDN=ix.x2chat.com] [EDGE_NAME=edge-r1] [SSH_ADMIN_IP=1.2.3.4] bash install_x2chat_edge_proxy.sh
USAGE
  exit 1
fi

echo "==> Installing base packages"
export DEBIAN_FRONTEND=noninteractive
sudo apt update
sudo apt install -y nginx certbot python3-certbot-nginx ufw fail2ban curl jq

echo "==> Enabling services"
sudo systemctl enable nginx
sudo systemctl start nginx
sudo systemctl enable fail2ban
sudo systemctl start fail2ban

echo "==> Configuring UFW"
sudo ufw --force enable || true
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow OpenSSH
if [[ -n "${SSH_ADMIN_IP}" ]]; then
  sudo ufw allow from "${SSH_ADMIN_IP}" to any port 22 proto tcp
fi
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp

echo "==> Writing temporary nginx config for ACME"
sudo mkdir -p /var/www/html/.well-known/acme-challenge
sudo tee /etc/nginx/sites-available/x2chat-edge.conf >/dev/null <<EOF
server {
    listen 80;
    listen [::]:80;
    server_name ${EDGE_FQDN};

    location /.well-known/acme-challenge/ { root /var/www/html; }

    location = /edge-health {
        add_header Content-Type text/plain;
        return 200 "ok\\n";
    }

    location / {
        return 301 https://\$host\$request_uri;
    }
}
EOF

sudo ln -sf /etc/nginx/sites-available/x2chat-edge.conf /etc/nginx/sites-enabled/x2chat-edge.conf
sudo rm -f /etc/nginx/sites-enabled/default
sudo nginx -t
sudo systemctl reload nginx

echo "==> Issuing TLS certificate"
sudo certbot certonly --webroot -w /var/www/html \
  -d "${EDGE_FQDN}" \
  --non-interactive --agree-tos -m "${ADMIN_EMAIL}" \
  --keep-until-expiring

echo "==> Writing production nginx config"
cat >/tmp/x2chat-edge.conf.tmpl <<'EOF'
map $http_upgrade $connection_upgrade {
    default upgrade;
    ''      close;
}

limit_req_zone $binary_remote_addr zone=x2_api_limit:20m rate=80r/s;

server {
    listen 80;
    listen [::]:80;
    server_name __EDGE_FQDN__;

    location /.well-known/acme-challenge/ { root /var/www/html; }
    location = /edge-health { add_header Content-Type text/plain; return 200 "ok\n"; }
    location / { return 301 https://$host$request_uri; }
}

server {
    listen 443 ssl http2;
    listen [::]:443 ssl http2;
    server_name __EDGE_FQDN__;

    ssl_certificate /etc/letsencrypt/live/__EDGE_FQDN__/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/__EDGE_FQDN__/privkey.pem;
    include /etc/letsencrypt/options-ssl-nginx.conf;

    server_tokens off;
    client_max_body_size 600m;
    add_header X-Edge-Node "__EDGE_NAME__" always;
    add_header Strict-Transport-Security "max-age=31536000" always;

    location = /edge-health {
        add_header Content-Type text/plain;
        return 200 "ok\n";
    }

    location /api/v1/notifications/stream {
        proxy_pass https://__ORIGIN_FQDN__;
        proxy_http_version 1.1;
        proxy_set_header Host __ORIGIN_FQDN__;
        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 https;
        proxy_set_header Connection '';
        proxy_connect_timeout 15s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffering off;
        proxy_cache off;
        gzip off;
        add_header X-Accel-Buffering no;
        proxy_ssl_server_name on;
        proxy_ssl_name __ORIGIN_FQDN__;
    }

    location /ws {
        proxy_pass https://__ORIGIN_FQDN__;
        proxy_http_version 1.1;
        proxy_set_header Host __ORIGIN_FQDN__;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection $connection_upgrade;
        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 https;
        proxy_connect_timeout 15s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_buffering off;
        proxy_ssl_server_name on;
        proxy_ssl_name __ORIGIN_FQDN__;
    }

    location /api/v1/updates/ {
        proxy_pass https://__ORIGIN_FQDN__;
        proxy_http_version 1.1;
        proxy_set_header Host __ORIGIN_FQDN__;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto https;
        proxy_request_buffering off;
        proxy_connect_timeout 15s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_ssl_server_name on;
        proxy_ssl_name __ORIGIN_FQDN__;
    }

    location /downloads/ {
        proxy_pass https://__ORIGIN_FQDN__;
        proxy_http_version 1.1;
        proxy_set_header Host __ORIGIN_FQDN__;
        proxy_set_header X-Forwarded-Proto https;
        proxy_connect_timeout 15s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_ssl_server_name on;
        proxy_ssl_name __ORIGIN_FQDN__;
    }

    location /apk/ {
        proxy_pass https://__ORIGIN_FQDN__;
        proxy_http_version 1.1;
        proxy_set_header Host __ORIGIN_FQDN__;
        proxy_set_header X-Forwarded-Proto https;
        proxy_connect_timeout 15s;
        proxy_read_timeout 3600s;
        proxy_send_timeout 3600s;
        proxy_ssl_server_name on;
        proxy_ssl_name __ORIGIN_FQDN__;
    }

    location / {
        limit_req zone=x2_api_limit burst=120 nodelay;
        proxy_pass https://__ORIGIN_FQDN__;
        proxy_http_version 1.1;
        proxy_set_header Host __ORIGIN_FQDN__;
        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 https;
        proxy_connect_timeout 15s;
        proxy_read_timeout 120s;
        proxy_send_timeout 120s;
        proxy_ssl_server_name on;
        proxy_ssl_name __ORIGIN_FQDN__;
    }
}
EOF

sed \
  -e "s/__EDGE_FQDN__/${EDGE_FQDN}/g" \
  -e "s/__ORIGIN_FQDN__/${ORIGIN_FQDN}/g" \
  -e "s/__EDGE_NAME__/${EDGE_NAME}/g" \
  /tmp/x2chat-edge.conf.tmpl | sudo tee /etc/nginx/sites-available/x2chat-edge.conf >/dev/null

sudo nginx -t
sudo systemctl reload nginx

echo "==> Configuring fail2ban"
sudo tee /etc/fail2ban/jail.d/x2chat-edge.local >/dev/null <<'EOF'
[sshd]
enabled = true

[nginx-http-auth]
enabled = true

[nginx-botsearch]
enabled = true
EOF
sudo systemctl restart fail2ban

echo "==> Enabling cert renew timer"
sudo systemctl enable certbot.timer || true
sudo systemctl start certbot.timer || true

echo "==> Smoke checks"
curl -fsS "https://${EDGE_FQDN}/edge-health"
curl -fsS "https://${EDGE_FQDN}/health" | jq .
curl -fsS "https://${EDGE_FQDN}/api/v1/updates/version" | jq .

echo
echo "SUCCESS"
echo "EDGE URL: https://${EDGE_FQDN}"
echo "Health: https://${EDGE_FQDN}/health"
echo "Edge health: https://${EDGE_FQDN}/edge-health"
