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

# Deckyard installer — from nothing to a running instance at
# http://localhost:4177. Picks the fastest path it can: Docker if you have it,
# otherwise a plain Node.js checkout. Safe to re-run: an existing install is
# updated in place, an existing .env is left alone.
#
# Usage:
#   curl -fsSL https://deckyard.eu/install.sh | bash
#   bash scripts/install.sh                 # from inside a clone
#
# Knobs (all optional, via environment):
#   DECKYARD_DIR     target directory (default: ./deckyard, ignored inside a clone)
#   DECKYARD_REPO    git URL to clone (default: the public repo)
#   DECKYARD_BRANCH  branch to check out (default: main)
#   DECKYARD_MODE    force "docker" or "node" instead of auto-detecting
#   PORT             app port (default: 4177)
#
# Read before you pipe: this is scripts/install.sh in the repo. It clones
# Deckyard, writes a *local* .env, installs dependencies, and starts the app.
# It sends none of your data anywhere. It does not install Docker or Node for
# you; if neither is present it tells you where to get them and stops.

REPO="${DECKYARD_REPO:-https://github.com/jaapstronks/deckyard.git}"
BRANCH="${DECKYARD_BRANCH:-main}"
DIR="${DECKYARD_DIR:-deckyard}"
PORT="${PORT:-4177}"
MODE="${DECKYARD_MODE:-}"

BOLD=$'\033[1m'; DIM=$'\033[2m'; GREEN=$'\033[32m'; YELLOW=$'\033[33m'; RED=$'\033[31m'; RESET=$'\033[0m'
say()  { printf '%s\n' "${BOLD}==>${RESET} $*"; }
note() { printf '%s\n' "${DIM}    $*${RESET}"; }
warn() { printf '%s\n' "${YELLOW}!! ${RESET} $*" >&2; }
die()  { printf '%s\n' "${RED}xx ${RESET} $*" >&2; exit 1; }
has()  { command -v "$1" >/dev/null 2>&1; }

open_browser() {
  local url="$1"
  if has open; then ( sleep 2; open "$url" >/dev/null 2>&1 || true ) &
  elif has xdg-open; then ( sleep 2; xdg-open "$url" >/dev/null 2>&1 || true ) &
  fi
}

node_major() { node -v 2>/dev/null | sed -E 's/^v([0-9]+).*/\1/'; }

# --- pick a mode -------------------------------------------------------------
docker_ok() { has docker && docker compose version >/dev/null 2>&1; }
node_ok()   { has node && [ "$(node_major)" -ge 22 ] 2>/dev/null; }

if [ -z "$MODE" ]; then
  if docker_ok; then MODE=docker
  elif node_ok; then MODE=node
  else
    die "Need either Docker (with the compose plugin) or Node.js 22+.
    Install Docker:  https://docs.docker.com/get-docker/
    Install Node 22: https://nodejs.org/  (or: nvm install 22)
    Then re-run this installer."
  fi
fi
[ "$MODE" = docker ] && ! docker_ok && die "DECKYARD_MODE=docker but Docker + compose plugin not found."
[ "$MODE" = node ]   && ! node_ok   && die "DECKYARD_MODE=node but Node.js 22+ not found (found: $(node -v 2>/dev/null || echo none))."

# --- get the source ----------------------------------------------------------
# Already inside a clone? Use it in place and ignore DECKYARD_DIR.
if [ -f package.json ] && grep -q '"name": "deckyard"' package.json 2>/dev/null && [ -f scripts/install.sh ]; then
  say "Running inside an existing Deckyard checkout — using it in place."
  DIR="."
elif [ -d "$DIR/.git" ]; then
  say "Updating existing install in ${BOLD}$DIR${RESET}…"
  has git || die "git is required to update the checkout. Install git and re-run."
  git -C "$DIR" fetch --quiet --prune origin
  git -C "$DIR" checkout --quiet "$BRANCH"
  git -C "$DIR" pull --quiet --ff-only origin "$BRANCH" || warn "Could not fast-forward (local changes?). Continuing with what's on disk."
else
  has git || die "git is required to clone Deckyard. Install git and re-run."
  say "Cloning Deckyard into ${BOLD}$DIR${RESET}…"
  git clone --quiet --branch "$BRANCH" "$REPO" "$DIR"
fi
cd "$DIR"

# --- configure (.env) --------------------------------------------------------
if [ -f .env ]; then
  say "Keeping existing .env (run ${BOLD}npm run setup${RESET} to change it)."
elif [ -t 0 ] && node_ok; then
  # Interactive terminal + Node available → run the friendly wizard.
  say "Configuring — a couple of quick questions (Enter accepts the default):"
  node scripts/setup.js || warn "Setup wizard exited early; falling back to a minimal .env."
fi
if [ ! -f .env ]; then
  # No TTY (piped install) or wizard skipped: write a minimal, boots-immediately
  # .env. Auth is explicitly disabled so the server does not refuse to start;
  # this is a local, single-user default. Turn auth on later with `npm run setup`.
  say "Writing a minimal .env (auth disabled — local single-user default)."
  {
    printf '# Generated by scripts/install.sh — see .env.example for every option.\n'
    printf 'PORT=%s\n' "$PORT"
    printf 'AUTH_ENABLED=false\n'
  } > .env
  note "To secure this instance later: npm run setup"
fi

URL="http://localhost:${PORT}"

# --- start -------------------------------------------------------------------
if [ "$MODE" = docker ]; then
  say "Building and starting containers (docker compose)…"
  docker compose up -d --build
  open_browser "$URL"
  printf '\n%s Deckyard is starting at %s%s%s\n' "${GREEN}✓${RESET}" "${BOLD}" "$URL" "${RESET}"
  note "Logs:  docker compose logs -f --tail=200"
  note "Stop:  docker compose down"
  exit 0
fi

# Node path.
say "Installing dependencies (npm install)…"
npm install

if [ -t 0 ]; then
  # Interactive terminal: start the server in the foreground (Ctrl-C to stop),
  # opening the browser once it's up.
  open_browser "$URL"
  printf '\n%s Starting Deckyard at %s%s%s  (Ctrl-C to stop)\n\n' "${GREEN}✓${RESET}" "${BOLD}" "$URL" "${RESET}"
  exec npm run start
else
  # Piped, non-interactive: don't hold the pipe open with a blocking server.
  # Hand the user the one command that finishes the job.
  printf '\n%s Deckyard is installed. Start it with:\n\n' "${GREEN}✓${RESET}"
  printf '    cd %s && npm run start\n\n' "$DIR"
  note "Then open $URL"
fi
