#!/bin/sh
# Usage: curl -fsSL https://cdn.bricks.tools/bricks-project-desktop/release/install.sh | sh
#        curl -fsSL ... | sh -s -- --beta   # install beta channel
#
# Installs CTOR on Linux by downloading the AppImage,
# placing it in ~/.local/bin, and optionally integrating with the desktop.

set -eu

# ─── Parse flags ──────────────────────────────────────────────────────
CHANNEL="release"
for arg in "$@"; do
  case "$arg" in
    --beta) CHANNEL="beta" ;;
  esac
done

# ─── Configuration ────────────────────────────────────────────────────
# Beta installs use distinct APP_NAME / DISPLAY_NAME / artifact names so they
# can coexist with a release install (separate binary, desktop entry, icons).
if [ "$CHANNEL" = "beta" ]; then
  APP_NAME="bricks-ctor-beta"
  DISPLAY_NAME="CTOR Beta"
  ARTIFACT_PREFIX="CTOR-Beta"
  WM_CLASS="ctor-beta"
else
  APP_NAME="bricks-ctor"
  DISPLAY_NAME="CTOR"
  ARTIFACT_PREFIX="CTOR"
  WM_CLASS="ctor"
fi
CDN_BASE="https://cdn.bricks.tools/bricks-project-desktop/${CHANNEL}"
INSTALL_DIR="${HOME}/.local/bin"
DESKTOP_DIR="${HOME}/.local/share/applications"
ICON_DIR="${HOME}/.local/share/icons"

# ─── Helpers ──────────────────────────────────────────────────────────
info()  { printf '\033[1;34m%s\033[0m %s\n' ">>" "$*"; }
ok()    { printf '\033[1;32m%s\033[0m %s\n' "✓ " "$*"; }
err()   { printf '\033[1;31m%s\033[0m %s\n' "✗ " "$*" >&2; }
die()   { err "$@"; exit 1; }

need_cmd() {
  command -v "$1" > /dev/null 2>&1 || die "Required command not found: $1"
}

ensure_install_dir_in_path() {
  case ":${PATH}:" in
    *":${INSTALL_DIR}:"*) return 0 ;;
  esac

  info "${INSTALL_DIR} is not in your PATH."

  USER_SHELL="$(basename "${SHELL:-sh}")"
  RC_FILE=""
  EXPORT_LINE=""
  APPLY_CMD=""

  case "$USER_SHELL" in
    bash)
      RC_FILE="${HOME}/.bashrc"
      EXPORT_LINE="export PATH=\"${INSTALL_DIR}:\$PATH\""
      APPLY_CMD="source \"${RC_FILE}\""
      ;;
    zsh)
      RC_FILE="${HOME}/.zshrc"
      EXPORT_LINE="export PATH=\"${INSTALL_DIR}:\$PATH\""
      APPLY_CMD="source \"${RC_FILE}\""
      ;;
    fish)
      RC_FILE="${HOME}/.config/fish/config.fish"
      EXPORT_LINE="set -gx PATH \"${INSTALL_DIR}\" \$PATH"
      APPLY_CMD="source \"${RC_FILE}\""
      ;;
    sh | dash | ash | ksh)
      RC_FILE="${HOME}/.profile"
      EXPORT_LINE="export PATH=\"${INSTALL_DIR}:\$PATH\""
      APPLY_CMD=". \"${RC_FILE}\""
      ;;
  esac

  if [ -n "$RC_FILE" ]; then
    if [ -f "$RC_FILE" ] && grep -qF "${INSTALL_DIR}" "$RC_FILE" 2>/dev/null; then
      info "PATH entry already exists in ${RC_FILE}; restart your shell to apply."
    else
      mkdir -p "$(dirname "$RC_FILE")"
      printf '\n# Added by %s installer\n%s\n' "$DISPLAY_NAME" "$EXPORT_LINE" >> "$RC_FILE"
      ok "Added ${INSTALL_DIR} to PATH in ${RC_FILE}"
      info "Restart your shell or run: ${APPLY_CMD}"
    fi
  else
    info "Add this to your shell profile (~/.bashrc, ~/.zshrc, etc.):"
    printf '\n  \033[1mexport PATH="%s:$PATH"\033[0m\n\n' "$INSTALL_DIR"
  fi
}

# ─── libfuse2 (AppImage runtime dependency) ──────────────────────────
has_libfuse2() {
  # ldconfig usually lives in /sbin which often isn't in non-root PATH
  if [ -x /sbin/ldconfig ]; then
    /sbin/ldconfig -p 2>/dev/null | grep -q 'libfuse.so.2' && return 0
  elif command -v ldconfig > /dev/null 2>&1; then
    ldconfig -p 2>/dev/null | grep -q 'libfuse.so.2' && return 0
  fi
  for dir in /usr/lib/x86_64-linux-gnu /usr/lib/aarch64-linux-gnu /usr/lib64 /usr/lib /lib; do
    [ -e "${dir}/libfuse.so.2" ] && return 0
  done
  return 1
}

ensure_libfuse2() {
  if has_libfuse2; then
    return 0
  fi

  info "libfuse2 not found — required to launch the AppImage."

  PKG_NAME=""
  INSTALL_CMD=""
  if command -v apt-get > /dev/null 2>&1; then
    if apt-cache show libfuse2 > /dev/null 2>&1; then
      PKG_NAME="libfuse2"
    elif apt-cache show libfuse2t64 > /dev/null 2>&1; then
      # Ubuntu 24.04+ ships libfuse2t64 (time_t 64-bit transition)
      PKG_NAME="libfuse2t64"
    else
      PKG_NAME="libfuse2"
    fi
    INSTALL_CMD="sudo apt-get update && sudo apt-get install -y ${PKG_NAME}"
  elif command -v dnf > /dev/null 2>&1; then
    PKG_NAME="fuse-libs"
    INSTALL_CMD="sudo dnf install -y ${PKG_NAME}"
  elif command -v yum > /dev/null 2>&1; then
    PKG_NAME="fuse-libs"
    INSTALL_CMD="sudo yum install -y ${PKG_NAME}"
  elif command -v pacman > /dev/null 2>&1; then
    PKG_NAME="fuse2"
    INSTALL_CMD="sudo pacman -S --noconfirm ${PKG_NAME}"
  elif command -v zypper > /dev/null 2>&1; then
    PKG_NAME="libfuse2"
    INSTALL_CMD="sudo zypper install -y ${PKG_NAME}"
  elif command -v apk > /dev/null 2>&1; then
    PKG_NAME="fuse"
    INSTALL_CMD="sudo apk add ${PKG_NAME}"
  else
    err "No supported package manager detected."
    err "Install libfuse2 (FUSE 2) manually before launching ${DISPLAY_NAME}."
    return 1
  fi

  info "Install command: ${INSTALL_CMD}"

  PROCEED=1
  if [ -t 0 ]; then
    printf '\033[1;34m>>\033[0m Install %s now? [Y/n] ' "$PKG_NAME"
    read -r REPLY
    case "$REPLY" in
      [nN]*) PROCEED=0 ;;
    esac
  else
    info "Installing ${PKG_NAME}..."
  fi

  if [ "$PROCEED" -eq 0 ]; then
    info "Skipped. Install ${PKG_NAME} later with the command above."
    return 0
  fi

  if sh -c "$INSTALL_CMD"; then
    ok "${PKG_NAME} installed"
  else
    err "Failed to install ${PKG_NAME}. Run the command above manually."
    return 1
  fi
}

# ─── Pre-flight checks ───────────────────────────────────────────────
need_cmd curl
need_cmd uname

OS="$(uname -s)"
ARCH="$(uname -m)"

case "$OS" in
  Linux) ;;
  *)     die "Unsupported OS: ${OS}. This installer is for Linux only." ;;
esac

case "$ARCH" in
  x86_64)  ARCH_SUFFIX="x86_64" ;;
  aarch64) ARCH_SUFFIX="arm64" ;;
  *)       die "Unsupported architecture: ${ARCH}" ;;
esac

info "Detected platform: Linux ${ARCH_SUFFIX}"
info "Channel: ${CHANNEL}"

# Soft check — proceed with download even if libfuse2 install fails so
# users can still grab the AppImage and fix the runtime dep later.
ensure_libfuse2 || true

# ─── Resolve latest release ──────────────────────────────────────────
info "Fetching latest ${CHANNEL} info..."

VERSION_JSON="$(curl -fsSL "${CDN_BASE}/version.json")" \
  || die "Failed to fetch version info from ${CDN_BASE}/version.json"

VERSION="$(printf '%s' "$VERSION_JSON" \
  | grep -o '"version" *: *"[^"]*"' \
  | head -1 \
  | sed 's/.*: *"//' \
  | sed 's/"$//')"

if [ -z "$VERSION" ]; then
  VERSION="latest"
fi

info "Latest version: ${VERSION}"

DOWNLOAD_URL="${CDN_BASE}/${ARTIFACT_PREFIX}-${ARCH_SUFFIX}.AppImage"

# ─── Download ─────────────────────────────────────────────────────────
mkdir -p "$INSTALL_DIR"

TARGET="${INSTALL_DIR}/${APP_NAME}"
TMP_TARGET="${TARGET}.download"

info "Downloading ${DISPLAY_NAME}..."
curl -fSL --progress-bar -o "$TMP_TARGET" "$DOWNLOAD_URL" \
  || die "Download failed from ${DOWNLOAD_URL}"

chmod +x "$TMP_TARGET"
mv "$TMP_TARGET" "$TARGET"

ok "Installed to ${TARGET}"

# ─── Desktop integration (optional) ──────────────────────────────────
setup_desktop() {
  mkdir -p "$DESKTOP_DIR"

  # Install multi-size icons to XDG hicolor theme for crisp dock rendering
  ICON_THEME_DIR="${HOME}/.local/share/icons/hicolor"
  for size in 48 128 256; do
    dest="${ICON_THEME_DIR}/${size}x${size}/apps"
    mkdir -p "$dest"
    curl -fsSL -o "${dest}/${APP_NAME}.png" "${CDN_BASE}/icons/${size}x${size}.png" 2>/dev/null || true
  done

  if command -v gtk-update-icon-cache > /dev/null 2>&1; then
    gtk-update-icon-cache -f -t "$ICON_THEME_DIR" 2>/dev/null || true
  fi

  cat > "${DESKTOP_DIR}/${APP_NAME}.desktop" <<EOF
[Desktop Entry]
Type=Application
Name=${DISPLAY_NAME}
Exec=${TARGET} --no-sandbox %U
Icon=${APP_NAME}
Terminal=false
Categories=Development;
StartupWMClass=${WM_CLASS}
Comment=${DISPLAY_NAME} — AI agent workspace
EOF

  if command -v update-desktop-database > /dev/null 2>&1; then
    update-desktop-database "$DESKTOP_DIR" 2>/dev/null || true
  fi

  ok "Desktop entry created — ${DISPLAY_NAME} should appear in your app launcher"
}

if [ -t 0 ]; then
  printf '\033[1;34m>>\033[0m Add to application launcher? [Y/n] '
  read -r REPLY
  case "$REPLY" in
    [nN]*) ;;
    *)     setup_desktop ;;
  esac
else
  setup_desktop
fi

# ─── PATH check ───────────────────────────────────────────────────────
ensure_install_dir_in_path

# ─── Done ─────────────────────────────────────────────────────────────
echo ""
ok "${DISPLAY_NAME} ${VERSION} is ready!"
info "Run it with:  ${APP_NAME}"
echo ""
