#!/bin/bash
# Tangly installer — POSIX (Linux/macOS).
#
# Usage:
#   curl -fsSL https://tangly.dev/install.sh | bash
#   curl -fsSL https://tangly.dev/install.sh | bash -s -- --version 0.0.5
#
# Env vars / flags:
#   TANGLY_VERSION  — pin to specific version. Default: latest.
#   TANGLY_BIN_DIR  — install dir for the `tangly` wrapper. Default: $HOME/.local/bin.
#   TANGLY_PM       — runner: "bun" | "npm". Default: bun if available, else npm.
#
# What this does
# --------------
# Tangly drives Astro programmatically at build time. Astro's plugin
# universe (vite, tailwind oxide native bindings, mdx, shiki, etc) needs
# real on-disk node_modules — not a single executable, not a global
# `npm install -g`. Globally-installed tangly fails to resolve transitive
# deps from inside your project dir because Node's upward module lookup
# doesn't reach the global install.
#
# Solution: install a thin wrapper at $TANGLY_BIN_DIR/tangly that delegates
# to `bunx --bun tangly@<version>` (or `npx tangly@<version>`) on every
# invocation. The package manager handles dep resolution correctly for
# each project. First run per version downloads ~80MB; subsequent runs
# hit the cache.
set -euo pipefail

if [ -t 1 ]; then
  RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[0;33m'; BLUE='\033[0;34m'; NC='\033[0m'
else
  RED=''; GREEN=''; YELLOW=''; BLUE=''; NC=''
fi
log()   { printf "%b==>%b %s\n" "$GREEN" "$NC" "$1" >&2; }
info()  { printf "%b::%b %s\n"  "$BLUE"  "$NC" "$1" >&2; }
warn()  { printf "%bWarning:%b %s\n" "$YELLOW" "$NC" "$1" >&2; }
error() { printf "%bError:%b %s\n" "$RED" "$NC" "$1" >&2; exit 1; }

VERSION="${TANGLY_VERSION:-latest}"
BIN_DIR="${TANGLY_BIN_DIR:-$HOME/.local/bin}"
PM_OVERRIDE="${TANGLY_PM:-auto}"

while [ $# -gt 0 ]; do
  case "$1" in
    --version) VERSION="$2"; shift 2 ;;
    --version=*) VERSION="${1#*=}"; shift ;;
    --bin-dir) BIN_DIR="$2"; shift 2 ;;
    --bin-dir=*) BIN_DIR="${1#*=}"; shift ;;
    --pm) PM_OVERRIDE="$2"; shift 2 ;;
    --pm=*) PM_OVERRIDE="${1#*=}"; shift ;;
    *) error "Unknown flag: $1" ;;
  esac
done

cat <<'EOF' >&2

  _____                _
 |_   _|_ _ _ __   __ _| |_   _
   | |/ _` | '_ \ / _` | | | | |
   | | (_| | | | | (_| | | |_| |
   |_|\__,_|_| |_|\__, |_|\__, |
                  |___/   |___/

EOF

pick_pm() {
  if [ "$PM_OVERRIDE" = "bun" ]; then
    command -v bun >/dev/null 2>&1 || error "TANGLY_PM=bun but 'bun' not found on PATH"
    echo bun; return
  fi
  if [ "$PM_OVERRIDE" = "npm" ]; then
    command -v npx >/dev/null 2>&1 || error "TANGLY_PM=npm but 'npx' not found on PATH"
    echo npm; return
  fi
  if command -v bun >/dev/null 2>&1; then echo bun; return; fi
  if command -v npx >/dev/null 2>&1; then echo npm; return; fi

  error "Neither bun nor npx found. Install one first:
  bun:  curl -fsSL https://bun.sh/install | bash
  node: https://nodejs.org/ (includes npm/npx)"
}

PM=$(pick_pm)
log "Runner: $PM"

# Resolve version → concrete pinned version (don't pin to "latest" in the
# wrapper because that would re-download every release).
if [ "$VERSION" = "latest" ]; then
  log "Resolving latest tangly version from npm…"
  if ! RESOLVED=$(curl -fsSL "https://registry.npmjs.org/tangly/latest" 2>/dev/null | sed -n 's/.*"version":"\([^"]*\)".*/\1/p' | head -1); then
    error "Failed to fetch tangly version from npm registry"
  fi
  if [ -z "$RESOLVED" ]; then
    error "Could not parse latest version from npm registry response"
  fi
  log "Latest: $RESOLVED"
  VERSION="$RESOLVED"
else
  VERSION="${VERSION#v}"
  log "Pinning to: $VERSION"
fi

mkdir -p "$BIN_DIR"
WRAPPER="$BIN_DIR/tangly"

cat > "$WRAPPER" <<EOF
#!/bin/bash
# Auto-generated by Tangly installer. Pinned to tangly@$VERSION.
# To upgrade: re-run the installer (or edit TANGLY_VERSION below).
TANGLY_VERSION="\${TANGLY_VERSION:-$VERSION}"
RUNNER="$PM"
case "\$RUNNER" in
  bun)
    exec bunx --bun "tangly@\$TANGLY_VERSION" "\$@"
    ;;
  npm)
    exec npx --yes "tangly@\$TANGLY_VERSION" "\$@"
    ;;
esac
EOF
chmod +x "$WRAPPER"

log "Wrote $WRAPPER (pinned tangly@$VERSION via $PM)"

# Warm the cache so the first real invocation is fast.
log "Warming cache…"
if "$WRAPPER" --version >/dev/null 2>&1; then
  info "Cache warmed."
else
  warn "Cache warm-up failed; first invocation will download deps."
fi

# PATH check
case ":$PATH:" in
  *":$BIN_DIR:"*) ;;
  *)
    warn "$BIN_DIR is not on PATH."
    info "Add it to your shell profile, e.g.:"
    case "${SHELL:-}" in
      */zsh)  info "  echo 'export PATH=\"$BIN_DIR:\$PATH\"' >> ~/.zshrc && source ~/.zshrc" ;;
      */fish) info "  echo 'fish_add_path $BIN_DIR' >> ~/.config/fish/config.fish" ;;
      *)      info "  echo 'export PATH=\"$BIN_DIR:\$PATH\"' >> ~/.bashrc && source ~/.bashrc" ;;
    esac
    ;;
esac

cat <<EOF >&2

${GREEN}Installed${NC}: tangly@$VERSION (wrapper at $WRAPPER)

Get started:
  mkdir my-docs && cd my-docs
  tangly init             # interactive scaffold
  tangly dev              # dev server
  tangly build            # static build → dist/

To upgrade later:
  curl -fsSL https://tangly.dev/install.sh | bash

Docs:    https://tangly.dev
Issues:  https://github.com/tanglydocs/tangly/issues
EOF
