#!/usr/bin/env bash
set -euo pipefail

repository="illia-antypenko/trit"
install_root="${TRIT_INSTALL_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/trit}"
bin_dir="${XDG_BIN_HOME:-$HOME/.local/bin}"
config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/trit"
systemd_dir="${XDG_CONFIG_HOME:-$HOME/.config}/systemd/user"

if [[ -f "$config_dir/env" ]]; then
  set -a
  # shellcheck disable=SC1090,SC1091
  source "$config_dir/env"
  set +a
fi

channel="${TRIT_CHANNEL:-beta}"
case "$channel" in
  stable|beta) ;;
  *)
    echo "trit: TRIT_CHANNEL must be stable or beta" >&2
    exit 1
    ;;
esac

if [[ "$(uname -s)" != Linux ]]; then
  echo "trit: only Linux is supported by the native installer" >&2
  exit 1
fi

case "$(uname -m)" in
  x86_64|amd64) architecture="x64" ;;
  arm64|aarch64) architecture="arm64" ;;
  *)
    echo "trit: unsupported architecture $(uname -m)" >&2
    exit 1
    ;;
esac

for command in curl tar sha256sum bwrap; do
  if ! command -v "$command" >/dev/null 2>&1; then
    echo "trit: $command is required" >&2
    exit 1
  fi
done

asset="trit-linux-${architecture}.tar.gz"
temporary_dir="$(mktemp -d)"
trap 'rm -rf -- "$temporary_dir"' EXIT

if [[ -n "${TRIT_INSTALL_ARCHIVE:-}" ]]; then
  cp -- "$TRIT_INSTALL_ARCHIVE" "$temporary_dir/$asset"
  if [[ -n "${TRIT_INSTALL_CHECKSUMS:-}" ]]; then
    cp -- "$TRIT_INSTALL_CHECKSUMS" "$temporary_dir/SHA256SUMS"
  else
    sha256sum "$temporary_dir/$asset" > "$temporary_dir/SHA256SUMS"
  fi
else
  if [[ -n "${TRIT_RELEASE_BASE_URL:-}" ]]; then
    release_url="${TRIT_RELEASE_BASE_URL%/}"
  elif [[ -n "${TRIT_INSTALL_VERSION:-}" ]]; then
    requested_version="${TRIT_INSTALL_VERSION#v}"
    if [[ ! "$requested_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+(-[0-9A-Za-z.-]+)?$ ]]; then
      echo "trit: invalid TRIT_INSTALL_VERSION" >&2
      exit 1
    fi
    download_origin="${TRIT_DOWNLOAD_ORIGIN:-https://downloads.trit.wtf}"
    release_url="${download_origin%/}/releases/v$requested_version"
  else
    download_origin="${TRIT_DOWNLOAD_ORIGIN:-https://downloads.trit.wtf}"
    release_url="${download_origin%/}/$channel"
  fi

  if ! curl --fail --silent --show-error --location "$release_url/$asset" --output "$temporary_dir/$asset"; then
    echo "trit: unable to download the $repository $channel release for linux-$architecture" >&2
    exit 1
  fi
  if ! curl --fail --silent --show-error --location "$release_url/SHA256SUMS" --output "$temporary_dir/SHA256SUMS"; then
    echo "trit: unable to download checksums for the $channel release" >&2
    exit 1
  fi
fi

expected="$(awk -v asset="$asset" '$2 == asset || $2 == "*" asset { print $1; exit }' "$temporary_dir/SHA256SUMS")"
actual="$(sha256sum "$temporary_dir/$asset" | awk '{ print $1 }')"
if [[ -z "$expected" || "$actual" != "$expected" ]]; then
  echo "trit: checksum verification failed for $asset" >&2
  exit 1
fi

tar -xzf "$temporary_dir/$asset" -C "$temporary_dir"
if [[ ! -f "$temporary_dir/trit/VERSION" ]]; then
  echo "trit: release archive is missing VERSION" >&2
  exit 1
fi
version="$(tr -d '[:space:]' < "$temporary_dir/trit/VERSION")"
target="$install_root/versions/$version"
previous=""
if [[ -L "$install_root/current" ]]; then
  previous="$(readlink -f -- "$install_root/current")"
fi

mkdir -p "$install_root/versions" "$bin_dir" "$config_dir" "$systemd_dir" "$config_dir/backups"
chmod 700 "$install_root" "$config_dir"

service_was_running=false
if [[ "${TRIT_NO_SYSTEMD:-0}" != 1 ]] && systemctl --user is-active --quiet trit.service 2>/dev/null; then
  service_was_running=true
  systemctl --user stop trit.service
fi

database_path="${TRIT_DB_PATH:-${TRIT_DATA_DIR:-${XDG_DATA_HOME:-$HOME/.local/share}/trit}/trit.db}"
backup_path=""
if [[ -n "$previous" && -f "$database_path" && -x "$previous/bin/trit" ]]; then
  backup_path="$config_dir/backups/pre-$version-$(date -u +%Y%m%dT%H%M%SZ).db"
  "$previous/bin/trit" backup "$backup_path" >/dev/null
fi

staged_target="$install_root/versions/.${version}.staging.$$"
replaced_target=""
mkdir -p "$staged_target"
cp -a "$temporary_dir/trit/." "$staged_target/"
chmod 755 "$staged_target/bin/trit" "$staged_target/runtime/bin/node"
if [[ -e "$target" ]]; then
  replaced_target="$install_root/versions/.${version}.previous.$$"
  mv -- "$target" "$replaced_target"
fi
mv -- "$staged_target" "$target"

projects_dir="$HOME/projects"
mkdir -p "$projects_dir"
if [[ ! -f "$config_dir/config.yaml" ]]; then
  cat > "$config_dir/config.yaml" <<EOF
agents:
  codex:
    registryId: codex-acp
projects:
  - name: projects
    path: $projects_dir
defaultAgent: codex
terminal:
  enabled: true
  backend: pty
updates:
  mode: download
EOF
  chmod 600 "$config_dir/config.yaml"
fi

if [[ ! -f "$config_dir/env" ]]; then
  cat > "$config_dir/env" <<EOF
NODE_ENV=production
TRIT_AUTH_MODE=local
TRIT_CHANNEL=$channel
TRIT_CONFIG=$config_dir/config.yaml
TRIT_DATA_DIR=${XDG_DATA_HOME:-$HOME/.local/share}/trit
HOST=127.0.0.1
PORT=9420
EOF
  chmod 600 "$config_dir/env"
fi

ln -s "$target" "$install_root/.current.$$"
mv -Tf "$install_root/.current.$$" "$install_root/current"
ln -sfn "$install_root/current/bin/trit" "$bin_dir/trit"
install -m 644 "$target/share/systemd/trit.service" "$systemd_dir/trit.service"
if [[ -f "$target/share/systemd/trit-update.service" ]]; then
  install -m 644 "$target/share/systemd/trit-update.service" "$systemd_dir/trit-update.service"
else
  rm -f -- "$systemd_dir/trit-update.service"
fi

rollback() {
  echo "trit: installation health check failed; rolling back" >&2
  systemctl --user stop trit.service >/dev/null 2>&1 || true
  if [[ -n "$previous" ]]; then
    ln -s "$previous" "$install_root/.current.rollback.$$"
    mv -Tf "$install_root/.current.rollback.$$" "$install_root/current"
  else
    rm -f -- "$install_root/current" "$bin_dir/trit"
  fi
  if [[ -n "$replaced_target" && -e "$replaced_target" ]]; then
    rm -rf -- "$target"
    mv -- "$replaced_target" "$target"
  fi
  if [[ -n "$backup_path" && -f "$backup_path" ]]; then
    install -m 600 "$backup_path" "$database_path"
    rm -f -- "$database_path-wal" "$database_path-shm"
  fi
  if [[ -n "$previous" ]]; then systemctl --user restart trit.service >/dev/null 2>&1 || true; fi
  exit 1
}

"$target/bin/trit" migrate >/dev/null || rollback

if [[ "${TRIT_NO_SYSTEMD:-0}" != 1 ]] && systemctl --user daemon-reload >/dev/null 2>&1; then
  if ! systemctl --user enable --now trit.service >/dev/null; then rollback; fi
  for _ in $(seq 1 40); do
    health="$(curl --fail --silent "http://127.0.0.1:${PORT:-9420}/health" 2>/dev/null || true)"
    if [[ "$health" == *"\"version\":\"$version\""* ]]; then
      if [[ -n "$replaced_target" ]]; then rm -rf -- "$replaced_target"; fi
      echo "Installed Trit $version"
      echo "Open http://127.0.0.1:${PORT:-9420}"
      exit 0
    fi
    sleep 0.25
  done
  rollback
fi

if [[ -n "$replaced_target" ]]; then rm -rf -- "$replaced_target"; fi
if [[ "$service_was_running" == true ]]; then
  echo "trit: the previous user service was stopped but systemd is unavailable" >&2
fi
echo "Installed Trit $version to $target"
echo "Run $bin_dir/trit serve"
