#!/usr/bin/env bash
# =============================================================================
# deploy-site.sh — host the gcprelay Django portal on the VM (or any Ubuntu box)
# behind gunicorn + nginx, optionally with HTTPS (Let's Encrypt + DuckDNS).
#
# Run ON the VM as a sudo-capable user, from inside the repo, e.g.:
#   sudo bash scripts/deploy-site.sh --host 34.14.201.15 --https \
#        --domain tyrostir.duckdns.org --ddns-token <duckdns-token> \
#        --email you@example.com
#
# Options (defaults):
#   --host HOST/IP           public IP for ALLOWED_HOSTS (default: *)
#   --repo GIT_URL           git clone URL (if not already in the repo dir)
#   --app-dir /opt/gcprelay  where the app lives on the server
#   --port 8000              gunicorn bind port (proxied by nginx)
#   --superuser USER         create a Django admin superuser (prompts password)
#   --https                  obtain a Let's Encrypt cert and force HTTPS
#   --domain NAME            TLS hostname, REQUIRED with --https (e.g.
#                            tyrostir.duckdns.org)
#   --email ADDR             Let's Encrypt registration email
#   --ddns-token TOKEN       DuckDNS token: point --domain at this box and keep
#                            it fresh via a 5-minute systemd timer
#   --no-nginx               gunicorn only (skip nginx)
#
# NOTE: opening tcp:80 and tcp:443 in the GCP firewall is done by provision-vm.sh
# (or run: gcloud compute firewall-rules create allow-https --allow=tcp:443 ...).
# =============================================================================
set -euo pipefail

HOST="*"; REPO=""; APP_DIR="/opt/gcprelay"; GPORT="8000"; SUPERUSER=""
DO_NGINX=1; DO_HTTPS=0; DOMAIN=""; EMAIL=""; DDNS_TOKEN=""
die(){ echo "ERROR: $*" >&2; exit 1; }
while [ $# -gt 0 ]; do case "$1" in
  --host) HOST="${2:-}"; shift 2;;
  --repo) REPO="${2:-}"; shift 2;;
  --app-dir) APP_DIR="${2:-}"; shift 2;;
  --port) GPORT="${2:-}"; shift 2;;
  --superuser) SUPERUSER="${2:-}"; shift 2;;
  --https) DO_HTTPS=1; shift;;
  --domain) DOMAIN="${2:-}"; shift 2;;
  --email) EMAIL="${2:-}"; shift 2;;
  --ddns-token) DDNS_TOKEN="${2:-}"; shift 2;;
  --no-nginx) DO_NGINX=0; shift;;
  -h|--help) sed -n '2,26p' "$0"; exit 0;;
  *) die "unknown arg: $1";;
esac; done
[ "$(id -u)" = 0 ] || die "run with sudo"

# HTTPS needs an explicit domain (DuckDNS or any DNS name pointing here).
if [ "$DO_HTTPS" = 1 ] && [ -z "$DOMAIN" ]; then
    die "--https requires --domain <name> (e.g. tyrostir.duckdns.org)"
fi
SERVER_NAME="_"; [ -n "$DOMAIN" ] && SERVER_NAME="$DOMAIN"

echo "==> [1/9] system packages"
apt-get update -y >/dev/null
apt-get install -y python3-venv python3-pip git nginx rsync >/dev/null

echo "==> [2/9] code -> $APP_DIR"
if [ -n "$REPO" ] && [ ! -d "$APP_DIR/.git" ]; then
    git clone "$REPO" "$APP_DIR"
elif [ -f "./manage.py" ]; then
    mkdir -p "$APP_DIR"; rsync -a --delete \
        --exclude .git --exclude .venv --exclude otp_codes --exclude db.sqlite3 \
        ./ "$APP_DIR"/
else
    [ -d "$APP_DIR" ] || die "no --repo and not inside the repo dir"
fi
cd "$APP_DIR"

echo "==> [3/9] virtualenv + deps"
[ -d .venv ] || python3 -m venv .venv
./.venv/bin/pip install --quiet --upgrade pip
./.venv/bin/pip install --quiet -r requirements.txt

echo "==> [4/9] environment (/etc/gcprelay.env)"
SECRET=$([ -f /etc/gcprelay.env ] && grep -oP '^DJANGO_SECRET_KEY=\K.*' /etc/gcprelay.env || \
         ./.venv/bin/python -c "import secrets;print(secrets.token_urlsafe(50))")
ALLOWED="$HOST"; [ -n "$DOMAIN" ] && ALLOWED="$HOST,$DOMAIN"
ORIGINS=""
[ "$HOST" != "*" ] && ORIGINS="http://$HOST"
[ -n "$DOMAIN" ] && ORIGINS="$ORIGINS,http://$DOMAIN,https://$DOMAIN"
cat > /etc/gcprelay.env <<ENV
DJANGO_SECRET_KEY=$SECRET
DJANGO_DEBUG=0
DJANGO_ALLOWED_HOSTS=$ALLOWED
DJANGO_CSRF_TRUSTED_ORIGINS=${ORIGINS#,}
DJANGO_DB_PATH=$APP_DIR/db.sqlite3
GCPRELAY_OTP_DIR=$APP_DIR/otp_codes
GCPRELAY_VM_IP=${DOMAIN:-$HOST}
ENV
chmod 600 /etc/gcprelay.env

echo "==> [5/9] migrate + collectstatic"
set -a; . /etc/gcprelay.env; set +a
./.venv/bin/python manage.py migrate --noinput
./.venv/bin/python manage.py collectstatic --noinput >/dev/null
mkdir -p "$APP_DIR/otp_codes"
if [ -n "$SUPERUSER" ]; then
    ./.venv/bin/python manage.py createsuperuser --username "$SUPERUSER" || true
fi
chown -R www-data:www-data "$APP_DIR"

echo "==> [6/9] gunicorn systemd service"
cat > /etc/systemd/system/gcprelay.service <<UNIT
[Unit]
Description=gcprelay Django portal (gunicorn)
After=network.target
[Service]
User=www-data
Group=www-data
WorkingDirectory=$APP_DIR
EnvironmentFile=/etc/gcprelay.env
ExecStart=$APP_DIR/.venv/bin/gunicorn gcprelay.wsgi:application --bind 127.0.0.1:$GPORT --workers 3
Restart=always
[Install]
WantedBy=multi-user.target
UNIT
systemctl daemon-reload
systemctl enable --now gcprelay.service
systemctl restart gcprelay.service
sleep 2
systemctl is-active gcprelay.service && echo "    gunicorn active"

if [ "$DO_NGINX" = 1 ]; then
echo "==> [7/9] nginx reverse proxy (server_name $SERVER_NAME)"
cat > /etc/nginx/sites-available/gcprelay <<NGINX
server {
    listen 80 default_server;
    server_name $SERVER_NAME;
    location / {
        proxy_pass http://127.0.0.1:$GPORT;
        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;
    }
}
NGINX
ln -sf /etc/nginx/sites-available/gcprelay /etc/nginx/sites-enabled/gcprelay
rm -f /etc/nginx/sites-enabled/default
nginx -t && systemctl reload nginx && echo "    nginx reloaded"
else
echo "==> [7/9] skipping nginx (--no-nginx)"
fi

if [ "$DO_HTTPS" = 1 ]; then
echo "==> [8/9] HTTPS via Let's Encrypt for $DOMAIN"
if [ -n "$DDNS_TOKEN" ]; then
    LABEL="${DOMAIN%.duckdns.org}"
    echo "    pointing DuckDNS '$LABEL' at this host + installing 5-min refresh"
    printf 'DUCKDNS_LABEL=%s\nDUCKDNS_TOKEN=%s\n' "$LABEL" "$DDNS_TOKEN" > /etc/duckdns.conf
    chmod 600 /etc/duckdns.conf
    cat > /usr/local/bin/duckdns-update.sh <<'DU'
#!/usr/bin/env bash
. /etc/duckdns.conf
# empty ip= makes DuckDNS use this host's public source IP (tracks ephemeral IP)
curl -fsS "https://www.duckdns.org/update?domains=${DUCKDNS_LABEL}&token=${DUCKDNS_TOKEN}&ip=" \
    -o /var/log/duckdns.log
DU
    chmod +x /usr/local/bin/duckdns-update.sh
    cat > /etc/systemd/system/duckdns.service <<'DS'
[Unit]
Description=DuckDNS IP update
After=network-online.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/duckdns-update.sh
DS
    cat > /etc/systemd/system/duckdns.timer <<'DT'
[Unit]
Description=Refresh DuckDNS every 5 minutes
[Timer]
OnBootSec=30
OnUnitActiveSec=5min
[Install]
WantedBy=timers.target
DT
    systemctl daemon-reload
    systemctl enable --now duckdns.timer >/dev/null 2>&1
    /usr/local/bin/duckdns-update.sh || true
    echo "    DuckDNS says: $(cat /var/log/duckdns.log 2>/dev/null)"
    sleep 6   # let DNS propagate before the HTTP-01 challenge
fi
apt-get install -y certbot python3-certbot-nginx >/dev/null
EMAIL_ARG="--register-unsafely-without-email"
[ -n "$EMAIL" ] && EMAIL_ARG="-m $EMAIL"
if certbot --nginx -d "$DOMAIN" --non-interactive --agree-tos $EMAIL_ARG --redirect; then
    echo "    certificate installed; HTTPS forced"
else
    echo "    WARNING: certbot failed (is tcp:80/443 open in the GCP firewall and"
    echo "    does $DOMAIN resolve to this box?). Site still works over HTTP."
fi
else
echo "==> [8/9] skipping HTTPS (--https not set)"
fi

echo "==> [9/9] done"
SCHEME="http"; [ "$DO_HTTPS" = 1 ] && SCHEME="https"
BASE="${DOMAIN:-$HOST}"
cat <<DONE

============================================================
 PORTAL DEPLOYED
============================================================
 URL:        $SCHEME://$BASE/gcprelay
 Admin:      $SCHEME://$BASE/gcprelay/admin/
 Service:    systemctl status gcprelay   |   journalctl -u gcprelay -f
 OTP codes:  $APP_DIR/otp_codes/{email,mobile,password_reset}_otps.txt
============================================================
DONE
