#!/bin/sh
# ForgePress one-line installer.
#
#   curl -fsSL https://get.opik.online | sudo bash
#
# Idempotent: safe to re-run after a failed install or to upgrade in place.
# Prints the panel URL and the seeded admin password on first run.

set -eu

if [ "$(id -u)" -ne 0 ]; then
  echo "ForgePress install requires root (use sudo)." >&2
  exit 1
fi

REPO=${FORGEPRESS_REPO:-very6778/forgepress}
FP_VERSION=${FORGEPRESS_VERSION:-latest}
FP_BRANCH=${FORGEPRESS_BRANCH:-container-arch}
PANEL_PORT=${FORGEPRESS_PORT:-8869}
INSTALL_PREFIX=${FORGEPRESS_PREFIX:-/opt/forgepress}
DATA_PREFIX=${FORGEPRESS_DATA:-/var/forgepress}
JWT_SECRET_FILE="$INSTALL_PREFIX/secrets/jwt"

say()  { printf '\033[1;34m[forgepress]\033[0m %s\n' "$1"; }
fail() { printf '\033[1;31m[forgepress]\033[0m %s\n' "$1" >&2; exit 1; }

# ── 1. Distro detection ─────────────────────────────────────────────────
[ -f /etc/os-release ] || fail "/etc/os-release not found — unsupported OS"
. /etc/os-release
case "${ID:-}" in
  ubuntu|debian) ;;
  *) fail "Unsupported distro '${ID:-unknown}'. ForgePress v1.0 supports Ubuntu/Debian only." ;;
esac

# ── 2. Architecture ─────────────────────────────────────────────────────
ARCH=$(uname -m)
case "$ARCH" in
  x86_64|amd64)  ARCH=amd64 ;;
  aarch64|arm64) ARCH=arm64 ;;
  *) fail "Unsupported arch '$ARCH' (need amd64 or arm64)." ;;
esac

# ── 3. Docker — install if missing ──────────────────────────────────────
if ! command -v docker >/dev/null 2>&1; then
  say "Docker not found — installing via get.docker.com"
  curl -fsSL https://get.docker.com | sh
fi
docker --version >/dev/null 2>&1 || fail "Docker did not install correctly."
systemctl enable --now docker >/dev/null 2>&1 || true

# ── 4. Layout + secrets ────────────────────────────────────────────────
install -d -m 755 "$INSTALL_PREFIX" "$INSTALL_PREFIX/secrets" "$INSTALL_PREFIX/data"
install -d -m 755 "$DATA_PREFIX" "$DATA_PREFIX/sites" "$DATA_PREFIX/data" "$DATA_PREFIX/backups"
chmod 700 "$INSTALL_PREFIX/secrets"

if [ ! -f "$JWT_SECRET_FILE" ]; then
  head -c 48 /dev/urandom | base64 | tr -d '/+=' > "$JWT_SECRET_FILE"
  chmod 600 "$JWT_SECRET_FILE"
fi

# Initial admin password — generated on first install, then preserved.
# Re-runs of install.sh keep the original (don't lock the operator out).
ADMIN_PW_FILE="$INSTALL_PREFIX/secrets/initial-admin-password"
if [ ! -f "$ADMIN_PW_FILE" ]; then
  head -c 18 /dev/urandom | base64 | tr -d '/+=' > "$ADMIN_PW_FILE"
  chmod 600 "$ADMIN_PW_FILE"
fi
ADMIN_PW=$(cat "$ADMIN_PW_FILE")

# ── 5. ForgePress binary ────────────────────────────────────────────────
say "Installing ForgePress binary ($FP_VERSION/$ARCH)"
TMP=$(mktemp)
trap 'rm -f "$TMP"' EXIT

if [ "$FP_VERSION" = "latest" ]; then
  URL="https://github.com/${REPO}/releases/latest/download/forgepress-linux-${ARCH}.tar.gz"
else
  URL="https://github.com/${REPO}/releases/download/${FP_VERSION}/forgepress-linux-${ARCH}.tar.gz"
fi

if curl -fsSL -o "$TMP" "$URL" 2>/dev/null; then
  tar -xzf "$TMP" -C /usr/local/bin/
  chmod +x /usr/local/bin/forgepress
else
  say "No release tarball — building from source (branch: $FP_BRANCH)"
  if ! command -v go >/dev/null 2>&1; then
    say "Installing Go toolchain"
    GO_VER=1.23.4
    curl -fsSL "https://go.dev/dl/go${GO_VER}.linux-${ARCH}.tar.gz" -o /tmp/go.tgz
    rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tgz && rm /tmp/go.tgz
    ln -sf /usr/local/go/bin/go /usr/local/bin/go
  fi
  command -v git >/dev/null 2>&1 || DEBIAN_FRONTEND=noninteractive apt-get -y -qq install git >/dev/null
  SRC=$(mktemp -d)
  git clone --depth 1 --branch "$FP_BRANCH" "https://github.com/${REPO}.git" "$SRC" >/dev/null 2>&1
  ( cd "$SRC" && go build -ldflags="-s -w" -o /usr/local/bin/forgepress ./cmd/wpforge ) || fail "build failed"
  rm -rf "$SRC"
fi
/usr/local/bin/forgepress --version 2>/dev/null || true

# ── 6. systemd unit ─────────────────────────────────────────────────────
cat > /etc/systemd/system/forgepress.service <<EOF
[Unit]
Description=ForgePress Panel
After=network-online.target docker.service
Requires=docker.service
Wants=network-online.target

[Service]
Type=simple
Environment=FORGEPRESS_PORT=${PANEL_PORT}
EnvironmentFile=${INSTALL_PREFIX}/secrets/env
ExecStart=/usr/local/bin/forgepress
Restart=on-failure
RestartSec=3
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

cat > "$INSTALL_PREFIX/secrets/env" <<EOF
JWT_SECRET=$(cat "$JWT_SECRET_FILE")
PORT=${PANEL_PORT}
DB_PATH=${DATA_PREFIX}/forgepress.db
FORGEPRESS_ADMIN_EMAIL=admin@forgepress.local
FORGEPRESS_ADMIN_PASSWORD=${ADMIN_PW}
EOF
chmod 600 "$INSTALL_PREFIX/secrets/env"

systemctl daemon-reload
systemctl enable --now forgepress

# ── 6b. UFW: pre-allow the panel port ──────────────────────────────────
# The server provisioner enables UFW with default deny-incoming and only
# opens 22/80/443. If we don't open the panel port BEFORE that, the
# operator gets locked out the moment they add the host as a managed
# server. Idempotent: `ufw allow` does nothing if the rule exists.
if command -v ufw >/dev/null 2>&1; then
  ufw allow "${PANEL_PORT}/tcp" >/dev/null 2>&1 || true
fi

# ── 7. Health check + first-run banner ──────────────────────────────────
say "Waiting for the panel to come up"
for i in $(seq 1 30); do
  if curl -fsS "http://127.0.0.1:${PANEL_PORT}/api/v1/health" >/dev/null 2>&1; then
    break
  fi
  sleep 1
done

IP=$(hostname -I | awk '{print $1}')
echo
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
say "ForgePress is up."
echo "  Panel:  http://${IP}:${PANEL_PORT}"
echo "  Email:  admin@forgepress.local"
echo "  Pass:   ${ADMIN_PW}"
echo "  (saved at ${ADMIN_PW_FILE} — change after first login)"
echo
echo "  → systemctl status forgepress"
echo "  → journalctl -u forgepress -f"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
