#!/bin/bash

# omarchy:summary=Install the Hermes desktop app
# omarchy:requires-sudo=true

set -e

if (( EUID == 0 )); then
  echo "Run this command as your desktop user, without sudo." >&2
  exit 1
fi

echo "Installing Hermes Desktop..."
omarchy-pkg-add hermes-desktop

if [[ ! -r /usr/share/hermes-desktop/install.sh || ! -r /usr/share/hermes-desktop/runtime.patch ]] ||
  ! release_commit=$(jq -er 'select(.branch == "main") | .commit | select(test("^[0-9a-f]{40}$"))' /opt/hermes-desktop/resources/install-stamp.json 2>/dev/null); then
  echo "The installed Hermes package cannot prepare in-app updates. Run 'omarchy update', then try again." >&2
  exit 1
fi

# If Hermes was already installed for the terminal, the app supersedes it: one
# machine, one Hermes. This drops that copy so the terminal, the default agent
# and the app all end up on the app's installation.
omarchy-install-hermes-cli || true

# Keep the runtime at the root even when invoked from a Hermes profile.
HERMES_HOME=$(realpath -ms -- "${HERMES_HOME:-$HOME/.hermes}")
home_parent=$(dirname -- "$HERMES_HOME")
if [[ ${home_parent##*/} == [Pp][Rr][Oo][Ff][Ii][Ll][Ee][Ss] ]]; then
  HERMES_HOME=$(dirname -- "$home_parent")
fi
export HERMES_HOME

runtime="$HERMES_HOME/hermes-agent"
native_app="$runtime/apps/desktop/release/linux-unpacked"

runtime_ready() {
  [[ -f $runtime/.hermes-bootstrap-complete && -f $runtime/venv/bin/hermes && -x $runtime/venv/bin/hermes && -f $runtime/venv/bin/python && -x $runtime/venv/bin/python ]] &&
    timeout 15 "$runtime/venv/bin/hermes" --version >/dev/null 2>&1
}

check_main() {
  local main_commit
  main_commit=$(git -C "$runtime" rev-parse --verify refs/heads/main 2>/dev/null || true)
  if [[ -n $main_commit && $main_commit != "$release_commit" && $main_commit != "$(git -C "$runtime" rev-parse --verify refs/remotes/origin/main 2>/dev/null)" ]]; then
    echo "Hermes main has local commits. Keep that work and prepare the desktop with 'hermes desktop --build-only'." >&2
    return 1
  fi
}

if ! runtime_ready; then
  # The upstream installer can reset an existing checkout. Do not pin a newer
  # or modified runtime back to the package release while repairing setup.
  if [[ -e $runtime || -L $runtime ]]; then
    if [[ $(git -C "$runtime" rev-parse HEAD 2>/dev/null) != "$release_commit" ]] ||
      [[ -n $(git -C "$runtime" status --porcelain --untracked-files=all) ]]; then
      echo "Hermes setup is incomplete at $runtime. Repair that installation before trying again; existing files have been kept." >&2
      exit 1
    fi
    check_main
  fi

  # Upstream replaces these commands, including foreign files and symlinks.
  # Keep their original bytes/links before handing the names to the desktop.
  command_backup=""
  for command in hermes hermes-agent hermes-acp; do
    command_path="$HOME/.local/bin/$command"
    if [[ -e $command_path || -L $command_path ]]; then
      if [[ ! -f $command_path && ! -L $command_path ]]; then
        echo "Cannot replace $command_path: move it aside before installing Hermes Desktop." >&2
        exit 1
      fi
      if [[ -z $command_backup ]]; then
        command_backup=$(mktemp -d "$HOME/.local/bin/.hermes-before-desktop.XXXXXX")
        echo "Saving existing Hermes commands in $command_backup"
      fi
      cp -a -- "$command_path" "$command_backup/"
    fi
  done

  echo "Setting up the Hermes runtime..."
  bash /usr/share/hermes-desktop/install.sh --skip-setup --branch main --commit "$release_commit" --force-commit --dir "$runtime" --hermes-home "$HERMES_HOME"
  if ! runtime_ready; then
    echo "Hermes runtime setup did not complete. Re-run this command after resolving the installer error." >&2
    exit 1
  fi
fi

runtime_commit=$(git -C "$runtime" rev-parse HEAD)
if [[ $runtime_commit == "$release_commit" ]]; then
  # The updater switches to main before checking for changes. Start main at
  # the packaged release, with enough history for its first fast-forward.
  check_main
  if [[ $(git -C "$runtime" rev-parse --is-shallow-repository) == "true" ]]; then
    git -C "$runtime" fetch --unshallow origin main
  fi
  git -C "$runtime" switch -C main "$release_commit"

  if git -C "$runtime" apply --check /usr/share/hermes-desktop/runtime.patch >/dev/null 2>&1; then
    git -C "$runtime" apply /usr/share/hermes-desktop/runtime.patch
  elif ! git -C "$runtime" apply --reverse --check /usr/share/hermes-desktop/runtime.patch >/dev/null 2>&1; then
    echo "The Hermes Linux runtime patch conflicts with local changes. Existing files have been kept." >&2
    exit 1
  fi
fi

if [[ -e $native_app || -L $native_app ]]; then
  if [[ ! -f $native_app/Hermes || ! -x $native_app/Hermes || ! -f $native_app/resources/app.asar || ! -f $native_app/resources/install-stamp.json ]]; then
    echo "The Hermes desktop app at $native_app is incomplete. Repair it with 'hermes desktop --build-only' before trying again." >&2
    exit 1
  fi
else
  if [[ $runtime_commit != "$release_commit" ]]; then
    echo "The Hermes runtime has moved beyond the packaged desktop release. Run 'hermes desktop --build-only', then try again." >&2
    exit 1
  fi
  desktop_changes=$(git -C "$runtime" status --porcelain --untracked-files=all -- apps/desktop package.json package-lock.json)
  if [[ -n $desktop_changes ]]; then
    echo "Hermes desktop sources have local changes. Run 'hermes desktop --build-only', then try again; existing files have been kept." >&2
    exit 1
  fi

  mkdir -p -- "${native_app%/*}"
  staging=$(mktemp -d "${native_app%/*}/.linux-unpacked.XXXXXX")
  trap 'rm -rf -- "$staging"' EXIT
  cp -a /opt/hermes-desktop/. "$staging/"
  chmod 0755 "$staging/chrome-sandbox"
  mv -T --no-clobber -- "$staging" "$native_app"
  if [[ -e $staging ]]; then
    echo "A Hermes desktop app appeared during setup. It has been kept; please try again." >&2
    exit 1
  fi
  trap - EXIT

  # Record this matching prebuilt app using the CLI's own content hash, so
  # subsequent menu launches do not rebuild an app that is already current.
  env -u PYTHONPATH -u PYTHONHOME "$runtime/venv/bin/python" - "$runtime" <<'PY'
import sys
from pathlib import Path

sys.path.insert(0, sys.argv[1])
if Path(sys.argv[1], "hermes_cli/main_desktop.py").is_file():
    from hermes_cli.main_desktop import _write_desktop_build_stamp
else:
    from hermes_cli.main import _write_desktop_build_stamp

_write_desktop_build_stamp(Path(sys.argv[1]), source_mode=False)
PY
fi

echo "Opening Hermes Desktop..."
setsid uwsm-app -- /usr/bin/hermes-desktop >/dev/null 2>&1 &

# Only a running Hermes can be told which skin to show; a unit outlives this
# terminal and reports to the journal.
echo "Matching Hermes to the current theme once it is set up..."
systemctl --user stop omarchy-hermes-theme.service 2>/dev/null || true
systemd-run --user --quiet --collect --unit=omarchy-hermes-theme omarchy-theme-set-hermes --wait

echo ""
echo "Hermes Desktop has been installed."
