#!/usr/bin/env bash
#
# exisvitae — Linux installer and updater.
#
#   curl -fsSL https://linux.exisvitae.com/install.sh | bash
#
# Rerun the same command to upgrade; it is a no-op when already current.
# Flags (pass them as: curl -fsSL … | bash -s -- --force):
#   --force      reinstall even when the installed build is already current
#   --uninstall  remove the app, its launcher and its icon
#
set -euo pipefail

CHANNEL="https://linux.exisvitae.com"
TARBALL_URL="$CHANNEL/exisvitae-linux.tar.gz"
VERSION_URL="$CHANNEL/version.json"

DATA_HOME="${XDG_DATA_HOME:-$HOME/.local/share}"
INSTALL_DIR="$DATA_HOME/exisvitae"
BIN_DIR="$HOME/.local/bin"
BIN_LINK="$BIN_DIR/exisvitae"
DESKTOP_FILE="$DATA_HOME/applications/com.exisvitae.desktop"
# The bundle ships a 1024x1024 icon, which fits no hicolor size directory,
# so the entry points at an absolute path instead (allowed by the spec).
ICON_FILE="$INSTALL_DIR/data/flutter_assets/assets/icon.png"

FORCE=0
UNINSTALL=0
for arg in "$@"; do
  case "$arg" in
    --force) FORCE=1 ;;
    --uninstall) UNINSTALL=1 ;;
    -h|--help)
      cat <<'USAGE'
exisvitae Linux installer and updater.

  curl -fsSL https://linux.exisvitae.com/install.sh | bash

Rerun the same command to upgrade; it is a no-op when already current.

Options (pass as: curl -fsSL ... | bash -s -- --force):
  --force      reinstall even when the installed build is already current
  --uninstall  remove the app, its launcher and its icon
USAGE
      exit 0 ;;
    *) echo "exisvitae: unknown option '$arg'" >&2; exit 2 ;;
  esac
done

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

# Reads a flat string field out of Flutter's version.json without needing jq.
json_field() { sed -n "s/.*\"$1\":\"\([^\"]*\)\".*/\1/p"; }

if [ "$UNINSTALL" = 1 ]; then
  rm -rf "$INSTALL_DIR"
  rm -f "$BIN_LINK" "$DESKTOP_FILE"
  command -v update-desktop-database >/dev/null 2>&1 &&
    update-desktop-database "$DATA_HOME/applications" >/dev/null 2>&1 || true
  say "exisvitae removed."
  exit 0
fi

[ "$(uname -s)" = "Linux" ] || die "This installer is for Linux; got $(uname -s)."
[ "$(uname -m)" = "x86_64" ] || die "Only x86_64 is published; this machine is $(uname -m)."
for tool in curl tar; do
  command -v "$tool" >/dev/null 2>&1 || die "'$tool' is required but not installed."
done

# The bundle links against system GTK 3; without it the binary starts and dies.
if ! ldconfig -p 2>/dev/null | grep -q 'libgtk-3\.so\.0'; then
  warn "libgtk-3 was not found. Install it before running the app, e.g."
  warn "  Debian/Ubuntu: sudo apt install libgtk-3-0"
  warn "  Fedora:        sudo dnf install gtk3"
fi

remote_meta="$(curl -fsSL "$VERSION_URL")" ||
  die "Cannot reach $VERSION_URL — is the release channel up?"
remote_build="$(printf '%s' "$remote_meta" | json_field build_number)"
remote_version="$(printf '%s' "$remote_meta" | json_field version)"
[ -n "$remote_build" ] || die "Release channel returned no build number."

local_build=""
local_version=""
if [ -f "$INSTALL_DIR/data/flutter_assets/version.json" ]; then
  local_build="$(json_field build_number < "$INSTALL_DIR/data/flutter_assets/version.json")"
  local_version="$(json_field version < "$INSTALL_DIR/data/flutter_assets/version.json")"
fi

if [ -n "$local_build" ] && [ "$local_build" = "$remote_build" ] && [ "$FORCE" = 0 ]; then
  say "Already on $local_version (build $local_build). Nothing to do."
  exit 0
fi

if [ "$local_build" = "$remote_build" ]; then
  say "Reinstalling $remote_version (build $remote_build)"
elif [ -n "$local_build" ]; then
  say "Upgrading $local_version (build $local_build) -> $remote_version (build $remote_build)"
else
  say "Installing exisvitae $remote_version (build $remote_build)"
fi

mkdir -p "$DATA_HOME" "$BIN_DIR" "$(dirname "$DESKTOP_FILE")"

# Staged next to the install dir so the final swap is a rename on one filesystem.
staging="$(mktemp -d "$DATA_HOME/.exisvitae-install-XXXXXX")"
cleanup() { rm -rf "$staging"; }
trap cleanup EXIT

say "Downloading $TARBALL_URL"
curl -fL --progress-bar "$TARBALL_URL" -o "$staging/bundle.tar.gz" ||
  die "Download failed."

mkdir -p "$staging/bundle"
tar -xzf "$staging/bundle.tar.gz" -C "$staging/bundle" || die "Archive is corrupt."
[ -x "$staging/bundle/exisvitae" ] || die "Archive has no exisvitae binary — bad release."

previous="$INSTALL_DIR.previous"
rm -rf "$previous"
if [ -d "$INSTALL_DIR" ]; then
  mv "$INSTALL_DIR" "$previous"
fi
mv "$staging/bundle" "$INSTALL_DIR"
rm -rf "$previous"

ln -sfn "$INSTALL_DIR/exisvitae" "$BIN_LINK"

cat > "$DESKTOP_FILE" <<DESKTOP
[Desktop Entry]
Type=Application
Name=exisvitae
Comment=exisvitae app
Exec="$INSTALL_DIR/exisvitae"
Icon=$ICON_FILE
Terminal=false
Categories=Utility;
StartupWMClass=com.exisvitae
DESKTOP

command -v update-desktop-database >/dev/null 2>&1 &&
  update-desktop-database "$DATA_HOME/applications" >/dev/null 2>&1 || true

say "Installed to $INSTALL_DIR"

case ":$PATH:" in
  *":$BIN_DIR:"*) say "Run it with:  exisvitae" ;;
  *) warn "$BIN_DIR is not on your PATH. Add it:"
     warn "  echo 'export PATH=\"\$HOME/.local/bin:\$PATH\"' >> ~/.bashrc && exec \$SHELL"
     say  "Or run it directly:  $INSTALL_DIR/exisvitae" ;;
esac
