#!/usr/bin/env bash
# DecisionManager Studio — one-shot install for macOS.
# Discovers an existing VS Code / VSCodium / Cursor app (even when the CLI is
# not on PATH), installs the Decision Manager VSIX, and opens the mode workspace.
# Homebrew install is a last resort only.
#
# Usage:
#   curl -fsSL https://YOUR_SITE/downloads/install-studio-macos.sh | bash
#   INSTALL_MODE=server BASE_URL=https://YOUR_SITE bash install-studio-macos.sh
#
# Cloud / air-gapped:
#   BASE_URL or STUDIO_BASE_URL  origin that serves /downloads/*.vsix
#   VSIX_URL                     full URL override for the extension package
#   INSTALL_MODE                 manager | server | admin (default manager)
#   FORCE_BREW_INSTALL=1         install/reinstall VSCodium via Homebrew even if an IDE exists
#
set -euo pipefail

PRODUCT="DecisionManager Studio"
MODE="${INSTALL_MODE:-manager}"
case "$MODE" in manager|server|admin) ;; *) MODE=manager ;; esac

# Origin that serves /downloads/*.vsix (defaults to the site that hosted this script).
if [[ -z "${BASE_URL:-}" ]]; then
  if [[ "${BASH_SOURCE[0]:-}" == http* ]]; then
    BASE_URL="$(dirname "${BASH_SOURCE[0]}")/.."
  else
    BASE_URL="${STUDIO_BASE_URL:-http://localhost:3003}"
  fi
fi
BASE_URL="${BASE_URL%/}"

VSIX_NAME="${VSIX_NAME:-decision-manager-0.4.5.vsix}"
VSIX_URL="${VSIX_URL:-$BASE_URL/downloads/$VSIX_NAME}"
TMP="${TMPDIR:-/tmp}/dm-studio-install-$$"
mkdir -p "$TMP"
trap 'rm -rf "$TMP"' EXIT

echo ""
echo "=== $PRODUCT — macOS install (mode: $MODE) ==="
echo "  base:  $BASE_URL"
echo "  vsix:  $VSIX_URL"
echo ""

# ── helpers ─────────────────────────────────────────────────────────────────
is_exec() {
  [[ -n "${1:-}" && -x "$1" && ! -d "$1" ]]
}

# Prefer absolute path so `curl | bash` non-login shells work without PATH hacks.
path_of() {
  local c
  c="$(command -v "$1" 2>/dev/null || true)"
  if is_exec "$c"; then
    echo "$c"
    return 0
  fi
  return 1
}

# Well-known GUI install locations (CLI often not on PATH until "Shell Command: Install").
well_known_clis() {
  local home="${HOME:-/Users/$(id -un)}"
  local candidates=(
    # VSCodium (preferred FLOSS host for Studio)
    "/Applications/VSCodium.app/Contents/Resources/app/bin/codium"
    "$home/Applications/VSCodium.app/Contents/Resources/app/bin/codium"
    "/opt/homebrew/bin/codium"
    "/usr/local/bin/codium"
    # Visual Studio Code
    "/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"
    "$home/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code"
    "/opt/homebrew/bin/code"
    "/usr/local/bin/code"
    # Insiders / OSS
    "/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code"
    "$home/Applications/Visual Studio Code - Insiders.app/Contents/Resources/app/bin/code"
    "/Applications/Code - OSS.app/Contents/Resources/app/bin/code"
    "$home/Applications/Code - OSS.app/Contents/Resources/app/bin/code"
    # Cursor (VS Code fork — accepts the same VSIX)
    "/Applications/Cursor.app/Contents/Resources/app/bin/cursor"
    "$home/Applications/Cursor.app/Contents/Resources/app/bin/cursor"
    "/opt/homebrew/bin/cursor"
    "/usr/local/bin/cursor"
  )
  local p
  for p in "${candidates[@]}"; do
    is_exec "$p" && echo "$p"
  done
}

# Order: PATH names first (user preference), then well-known bundles.
# Preference among discovered: codium > code-oss > code > code-insiders > cursor
pick_cli() {
  local found=()
  local name p
  for name in codium code-oss code code-insiders cursor; do
    if p="$(path_of "$name")"; then
      found+=("$p")
    fi
  done
  while IFS= read -r p; do
    [[ -n "$p" ]] || continue
    local already=0 f
    for f in "${found[@]:-}"; do
      [[ "$f" == "$p" ]] && { already=1; break; }
    done
    [[ $already -eq 0 ]] && found+=("$p")
  done < <(well_known_clis)

  if [[ ${#found[@]} -eq 0 ]]; then
    return 1
  fi

  # Rank: codium preferred, then code-oss, code, insiders, cursor
  local rank best="" best_score=999 score base
  for p in "${found[@]}"; do
    base="$(basename "$p")"
    case "$base" in
      codium) score=0 ;;
      code-oss) score=1 ;;
      code) score=2 ;;
      code-insiders) score=3 ;;
      cursor) score=4 ;;
      *) score=5 ;;
    esac
    # Prefer /Applications over Homebrew bin when same rank
    [[ "$p" == /Applications/* ]] && score=$((score))
    [[ "$p" == /opt/homebrew/* || "$p" == /usr/local/* ]] && score=$((score + 10))
    if [[ $score -lt $best_score ]]; then
      best_score=$score
      best="$p"
    fi
  done
  echo "$best"
}

# Log to stderr so command substitutions only capture the CLI path on stdout.
log() { printf '%s\n' "$*" >&2; }

# One-line re-run (same BASE_URL / INSTALL_MODE) after the user installs an IDE.
rerun_cmd() {
  printf 'curl -fsSL "%s/downloads/install-studio-macos.sh" | INSTALL_MODE=%s BASE_URL=%s bash' \
    "$BASE_URL" "$MODE" "$BASE_URL"
}

ensure_cli() {
  local cli
  if [[ "${FORCE_BREW_INSTALL:-0}" != "1" ]]; then
    if cli="$(pick_cli)"; then
      printf '%s\n' "$cli"
      return 0
    fi
  fi

  log "No VS Code / VSCodium / Cursor CLI found in PATH or /Applications."
  if ! command -v brew >/dev/null 2>&1; then
    # Try common Homebrew locations when non-login shell has empty PATH
    for brew_bin in /opt/homebrew/bin/brew /usr/local/bin/brew; do
      if is_exec "$brew_bin"; then
        # shellcheck disable=SC1091
        eval "$("$brew_bin" shellenv)"
        break
      fi
    done
  fi

  if command -v brew >/dev/null 2>&1; then
    log "Installing VSCodium via Homebrew (one-time; ~1-2 min)..."
    export HOMEBREW_NO_AUTO_UPDATE="${HOMEBREW_NO_AUTO_UPDATE:-1}"
    export HOMEBREW_NO_ENV_HINTS="${HOMEBREW_NO_ENV_HINTS:-1}"
    # Prefer VSCodium; fall back to VS Code if the cask is unavailable.
    if ! brew install --cask vscodium; then
      log "VSCodium cask failed - trying Visual Studio Code..."
      brew install --cask visual-studio-code || true
    fi
    # Refresh PATH for brew shims in this shell
    if [[ -x /opt/homebrew/bin/brew ]]; then
      eval "$(/opt/homebrew/bin/brew shellenv)"
    elif [[ -x /usr/local/bin/brew ]]; then
      eval "$(/usr/local/bin/brew shellenv)"
    fi
    # Give the cask a moment to materialise the app bundle, then re-probe well-known paths.
    sleep 1
    if cli="$(pick_cli)"; then
      printf '%s\n' "$cli"
      return 0
    fi
    log "error: Homebrew finished but no IDE CLI is usable yet."
    log "Open VSCodium once from /Applications (clear Gatekeeper if prompted), then re-run:"
    log "  $(rerun_cmd)"
    exit 1
  fi

  # No brew on PATH — single preferred path, not a menu of options.
  log ""
  log "Next (one command — install VSCodium, then finish Studio):"
  log "  brew install --cask vscodium && $(rerun_cmd)"
  log ""
  log "No Homebrew yet? https://brew.sh — then run the same one-liner."
  exit 1
}

CLI="$(ensure_cli)"
# ensure_cli may emit log lines; keep only the last non-empty line as the path
CLI="$(printf '%s\n' "$CLI" | awk 'NF { line=$0 } END { print line }')"
if [[ -z "$CLI" || ! -x "$CLI" ]]; then
  echo "error: could not resolve a usable IDE CLI path"
  exit 1
fi
CLI_LABEL="$(basename "$CLI")"
echo "Using IDE CLI: ${CLI_LABEL}"
echo "  path: ${CLI}"

# --- Download VSIX ---
echo "Downloading extension..."
curl -fL --progress-bar -o "${TMP}/${VSIX_NAME}" "${VSIX_URL}"

# --- Install extension ---
echo "Installing extension into ${CLI_LABEL}..."
"${CLI}" --install-extension "${TMP}/${VSIX_NAME}" --force

# --- Mode workspace (portable; never monorepo-relative under $TMP) ---
# Staged *.code-workspace files target the repo tree. End-user install downloads
# them into a throwaway dir, so relative folders and EXIT-trap cleanup break
# "open". Write a durable, settings-preserving workspace under
# ~/.decision-manager-studio/ with a single empty folder, then open that.
STUDIO_HOME="${HOME}/.decision-manager-studio"
mkdir -p "${STUDIO_HOME}/workspace"
WS_URL="${BASE_URL}/downloads/studio-workspaces/${MODE}.code-workspace"
WS_RAW="${TMP}/${MODE}.code-workspace.raw"
WS_FILE="${STUDIO_HOME}/${MODE}.code-workspace"

write_portable_workspace() {
  local src="$1" dest="$2" mode="$3"
  # Prefer python3 (macOS ships it) to keep mode-specific settings from the staged file.
  if command -v python3 >/dev/null 2>&1; then
    if python3 - "$src" "$dest" "$mode" <<'PY'
import json, sys
src, dest, mode = sys.argv[1], sys.argv[2], sys.argv[3]
try:
    data = json.load(open(src, encoding="utf-8"))
except Exception:
    data = {}
if not isinstance(data, dict):
    data = {}
data["folders"] = [
    {"name": f"DecisionManager Studio ({mode})", "path": "workspace"}
]
data.setdefault("settings", {})
if not isinstance(data["settings"], dict):
    data["settings"] = {}
data.setdefault(
    "extensions",
    {"recommendations": ["decisionmanager.decision-manager"]},
)
json.dump(data, open(dest, "w", encoding="utf-8"), indent=2)
print("ok")
PY
    then
      return 0
    fi
  fi
  # Fallback: minimal settings-only workspace (same default API ports as staged files).
  cat >"$dest" <<EOF
{
  "folders": [
    { "name": "DecisionManager Studio (${mode})", "path": "workspace" }
  ],
  "settings": {
    "decisionManager.platformUrl": "http://localhost:8081",
    "decisionManager.managerUrl": "http://localhost:8082",
    "decisionManager.runtimeUrl": "http://localhost:8083",
    "decisionManager.adminUrl": "http://localhost:8084",
    "decisionManager.adminConsoleUrl": "http://localhost:3002"
  },
  "extensions": {
    "recommendations": ["decisionmanager.decision-manager"]
  }
}
EOF
}

OPENED=0
if curl -fsSL -o "${WS_RAW}" "${WS_URL}" 2>/dev/null && [[ -s "${WS_RAW}" ]]; then
  if write_portable_workspace "${WS_RAW}" "${WS_FILE}" "${MODE}"; then
    echo "Opening ${MODE} workspace (portable profile at ${WS_FILE})..."
    # Open from STUDIO_HOME so relative folder "workspace" resolves.
    (cd "${STUDIO_HOME}" && "${CLI}" "${WS_FILE}") || "${CLI}" "${WS_FILE}" || true
    OPENED=1
  fi
fi

if [[ "${OPENED}" -eq 0 ]]; then
  echo '{}' >"${TMP}/empty.json"
  write_portable_workspace "${TMP}/empty.json" "${WS_FILE}" "${MODE}" || true
  if [[ -s "${WS_FILE}" ]]; then
    echo "Opening ${MODE} workspace (generated profile at ${WS_FILE})..."
    (cd "${STUDIO_HOME}" && "${CLI}" "${WS_FILE}") || "${CLI}" "${WS_FILE}" || true
    OPENED=1
  fi
fi

if [[ "${OPENED}" -eq 0 ]]; then
  echo "Extension installed. Sign in from the palette: Decision Manager: Sign In"
  echo "Configure platformUrl / managerUrl / runtimeUrl / adminUrl (ports 8081-8084)."
  "${CLI}" || true
fi

echo ""
echo "=== ${PRODUCT} ready (mode: ${MODE}) ==="
echo "  Sign In -> Decision Manager: Sign In"
echo "  Workspace: ${WS_FILE}"
echo "  Four URLs: platform :8081 · manager :8082 · runtime :8083 · admin :8084"
echo "  Cloud stack: point BASE_URL at your release host; instance URLs at your APIs."
echo ""
