#!/bin/sh
# Shopnex installer for Debian / Ubuntu servers.
#
#   curl -fsSL https://shopnex.ai/install.sh | sh
#   curl -fsSL https://shopnex.ai/install.sh | SHOPNEX_DOMAIN=shop.example.com sh
#
# Installs Node, Postgres and Shopnex (admin + storefront), runs them as systemd services and, when
# SHOPNEX_DOMAIN is set, puts Caddy in front of it for automatic HTTPS. Safe to re-run:
# it keeps your database and .env, and updates the code.
#
# Options (environment variables):
#   SHOPNEX_DOMAIN   public domain (DNS must already point at this server). Default: this server's IP on :80
#   SHOPNEX_DIR      install directory                                      Default: /opt/shopnex
#   SHOPNEX_REF      git branch or tag to install                           Default: v2
#   SHOPNEX_REPO     git repository                                         Default: github.com/shopnex-ai/shopnex
set -eu

SHOPNEX_DIR="${SHOPNEX_DIR:-/opt/shopnex}"
SHOPNEX_REF="${SHOPNEX_REF:-v2}"
SHOPNEX_REPO="${SHOPNEX_REPO:-https://github.com/shopnex-ai/shopnex.git}"
SHOPNEX_DOMAIN="${SHOPNEX_DOMAIN:-}"
NODE_MAJOR=24

say() { printf '\n\033[1m==> %s\033[0m\n' "$1"; }
die() { printf '\033[31mError: %s\033[0m\n' "$1" >&2; exit 1; }

# ── checks ───────────────────────────────────────────────────────────────────
[ "$(uname -s)" = "Linux" ] || die "This installer supports Debian/Ubuntu Linux. On macOS or Windows, see https://shopnex.ai/download#manual"
command -v apt-get >/dev/null 2>&1 || die "apt-get not found. This installer supports Debian and Ubuntu; see https://shopnex.ai/download#manual for other systems."

if [ "$(id -u)" -eq 0 ]; then
  SUDO=""
else
  command -v sudo >/dev/null 2>&1 || die "Run as root, or install sudo."
  SUDO="sudo"
fi

export DEBIAN_FRONTEND=noninteractive

# ── system packages ──────────────────────────────────────────────────────────
say "Installing system packages"
$SUDO apt-get update -qq
$SUDO apt-get install -y -qq ca-certificates curl git gnupg openssl postgresql >/dev/null

node_ok() { command -v node >/dev/null 2>&1 && [ "$(node -p 'process.versions.node.split(".")[0]')" -ge "$NODE_MAJOR" ]; }
if ! node_ok; then
  say "Installing Node.js $NODE_MAJOR"
  curl -fsSL "https://deb.nodesource.com/setup_${NODE_MAJOR}.x" | $SUDO -E bash - >/dev/null
  $SUDO apt-get install -y -qq nodejs >/dev/null
fi
$SUDO corepack enable

# ── database ─────────────────────────────────────────────────────────────────
ENV_FILE="$SHOPNEX_DIR/.env"
if [ -f "$ENV_FILE" ]; then
  say "Keeping existing $ENV_FILE"
else
  say "Creating the database"
  DB_PASSWORD="$(openssl rand -hex 16)"
  $SUDO systemctl enable --now postgresql >/dev/null 2>&1 || true
  if ! $SUDO -u postgres psql -tAc "SELECT 1 FROM pg_roles WHERE rolname='shopnex'" | grep -q 1; then
    $SUDO -u postgres psql -qc "CREATE ROLE shopnex LOGIN PASSWORD '$DB_PASSWORD'"
  else
    $SUDO -u postgres psql -qc "ALTER ROLE shopnex PASSWORD '$DB_PASSWORD'"
  fi
  $SUDO -u postgres psql -tAc "SELECT 1 FROM pg_database WHERE datname='shopnex'" | grep -q 1 \
    || $SUDO -u postgres createdb -O shopnex shopnex
fi

# ── code ─────────────────────────────────────────────────────────────────────
say "Fetching Shopnex ($SHOPNEX_REF)"
id shopnex >/dev/null 2>&1 || $SUDO useradd --system --create-home --home-dir /var/lib/shopnex --shell /usr/sbin/nologin shopnex
if [ -d "$SHOPNEX_DIR/.git" ]; then
  $SUDO git -C "$SHOPNEX_DIR" fetch --depth 1 origin "$SHOPNEX_REF" -q
  $SUDO git -C "$SHOPNEX_DIR" checkout -q -f FETCH_HEAD
else
  $SUDO git clone --depth 1 --branch "$SHOPNEX_REF" -q "$SHOPNEX_REPO" "$SHOPNEX_DIR"
fi

if [ -n "$SHOPNEX_DOMAIN" ]; then
  APP_ORIGIN="https://$SHOPNEX_DOMAIN"
else
  IP="$(curl -fsS --max-time 5 https://api.ipify.org 2>/dev/null || hostname -I | cut -d' ' -f1)"
  APP_ORIGIN="http://$IP"
fi

if [ ! -f "$ENV_FILE" ]; then
  $SUDO sh -c "umask 077 && cat > '$ENV_FILE'" <<EOF
DATABASE_URL=postgres://shopnex:$DB_PASSWORD@localhost:5432/shopnex
BETTER_AUTH_SECRET=$(openssl rand -hex 32)
BETTER_AUTH_URL=$APP_ORIGIN
APP_URL=$APP_ORIGIN
TENANCY_MODE=single
DEFAULT_SHOP_NAME="My Shop"
PORT=3000
NODE_ENV=production
EOF
fi
$SUDO chown -R shopnex:shopnex "$SHOPNEX_DIR"

# ── build ────────────────────────────────────────────────────────────────────
say "Installing dependencies and building (a few minutes)"
run_app() { $SUDO -u shopnex -H sh -c "cd '$SHOPNEX_DIR' && set -a && . ./.env && set +a && $1"; }
run_app "pnpm install --frozen-lockfile"
run_app "pnpm db:migrate"
run_app "pnpm build"
run_app "pnpm --dir templates/storefront build"

# ── service ──────────────────────────────────────────────────────────────────
say "Starting Shopnex"
$SUDO tee /etc/systemd/system/shopnex.service >/dev/null <<EOF
[Unit]
Description=Shopnex admin, API and checkout
After=network.target postgresql.service

[Service]
User=shopnex
WorkingDirectory=$SHOPNEX_DIR/apps/admin-ui
EnvironmentFile=$ENV_FILE
ExecStart=$(command -v node) server.mjs
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF
$SUDO tee /etc/systemd/system/shopnex-storefront.service >/dev/null <<EOF
[Unit]
Description=Shopnex storefront
After=shopnex.service

[Service]
User=shopnex
WorkingDirectory=$SHOPNEX_DIR/templates/storefront
Environment=HOST=127.0.0.1 PORT=4321 SHOPNEX_URL=http://localhost:3000 SHOPNEX_PUBLIC_URL=$APP_ORIGIN
ExecStart=$(command -v node) dist/server/entry.mjs
Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target
EOF
$SUDO systemctl daemon-reload
$SUDO systemctl enable shopnex shopnex-storefront >/dev/null 2>&1
$SUDO systemctl restart shopnex shopnex-storefront

# ── reverse proxy ────────────────────────────────────────────────────────────
say "Setting up the web server (Caddy)"
if ! command -v caddy >/dev/null 2>&1; then
  $SUDO apt-get install -y -qq debian-keyring debian-archive-keyring apt-transport-https >/dev/null
  curl -fsSL https://dl.cloudsmith.io/public/caddy/stable/gpg.key | $SUDO gpg --batch --yes --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
  curl -fsSL https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt | $SUDO tee /etc/apt/sources.list.d/caddy-stable.list >/dev/null
  $SUDO apt-get update -qq
  $SUDO apt-get install -y -qq caddy >/dev/null
fi
SITE_ADDRESS="${SHOPNEX_DOMAIN:-:80}"
# Admin, API and checkout go to the admin app; everything else is the storefront
$SUDO tee /etc/caddy/Caddyfile >/dev/null <<EOF
$SITE_ADDRESS {
	@admin path /admin /admin/* /api/* /checkout/* /assets/* /fonts/* /favicon.svg
	handle @admin {
		reverse_proxy localhost:3000
	}
	handle {
		reverse_proxy localhost:4321
	}
}
EOF
$SUDO systemctl enable caddy >/dev/null 2>&1
$SUDO systemctl reload caddy 2>/dev/null || $SUDO systemctl restart caddy

# ── done ─────────────────────────────────────────────────────────────────────
say "Shopnex is running"
printf '\nYour shop is at %s and the admin at %s/admin.\nOpen the admin to finish the setup wizard and create your shop and account.\n' "$APP_ORIGIN" "$APP_ORIGIN"
printf 'Config: %s   Logs: journalctl -u shopnex -f\n' "$ENV_FILE"
printf 'Update: re-run the same install command.\n\n'
