#!/bin/sh
#
# NeuraCore installer.
#
#   curl -fsSL https://download.neuracore.ch/install.sh | sudo sh
#
# On Linux, this adds the NeuraCore package repository and its signing key,
# then installs NeuraCore from it as an ordinary package.
# On macOS, this downloads the signed application bundle, installs it to
# /Applications, clears the quarantine mark, and symlinks the terminal command.
#
# It is generated by NeuraCoreDeploy and carries this release's signing
# fingerprint. Read it before running it; that is what the pipe into `sh`
# deserves.

set -eu

SITE="https://download.neuracore.ch"
KEY_FINGERPRINT="85D8D6B36EE7AD08922E94405401ED04C8BE02A8"

say() { printf '%s\n' "$*"; }
fail() { printf '%s\n' "$*" >&2; exit 1; }

# Root is needed to install software, and asking for it up front is better than
# failing halfway through with a permission error.
[ "$(id -u)" = "0" ] || fail "Please run this with sudo:  curl -fsSL $SITE/install.sh | sudo sh"

OS="$(uname -s)"
if [ "$OS" = "Darwin" ]; then
    say "macOS detected. Installing NeuraCore ..."

    command -v curl >/dev/null 2>&1 || fail "curl is required to install NeuraCore."
    command -v tar >/dev/null 2>&1 || fail "tar is required to unpack NeuraCore."

    say "Checking latest release from $SITE/latest.json ..."
    LATEST_JSON=$(curl -fsSL "$SITE/latest.json" 2>/dev/null || true)
    TARBALL_PATH=$(printf '%s\n' "$LATEST_JSON" | grep -o 'files/[^"]*macos[^"]*\.tar\.gz' | head -n 1 || true)
    if [ -z "$TARBALL_PATH" ]; then
        VERSION=$(printf '%s\n' "$LATEST_JSON" | grep -o '"version"[[:space:]]*:[[:space:]]*"[^"]*"' | head -n 1 | cut -d'"' -f4 || true)
        if [ -n "$VERSION" ]; then
            TARBALL_PATH="files/$VERSION/NeuraCore-$VERSION-macos.tar.gz"
        fi
    fi

    if [ -z "$TARBALL_PATH" ]; then
        for V in 2.0.0 1.0.1 1.0.0; do
            if curl -fsI "$SITE/files/$V/NeuraCore-$V-macos.tar.gz" 2>/dev/null | grep -q "200 OK"; then
                TARBALL_PATH="files/$V/NeuraCore-$V-macos.tar.gz"
                break
            fi
        done
    fi

    [ -n "$TARBALL_PATH" ] || fail "Could not locate a macOS release archive on $SITE."

    DOWNLOAD_URL="$SITE/$TARBALL_PATH"
    TMPDIR=$(mktemp -d /tmp/neuracore.XXXXXX)
    trap 'rm -rf "$TMPDIR"' EXIT INT TERM

    say "Downloading $DOWNLOAD_URL ..."
    curl -fsSL "$DOWNLOAD_URL" -o "$TMPDIR/macos.tar.gz" || fail "Failed to download NeuraCore from $DOWNLOAD_URL"

    say "Extracting archive ..."
    tar -xzf "$TMPDIR/macos.tar.gz" -C "$TMPDIR" || fail "Failed to extract NeuraCore archive."

    APP_SRC=""
    if [ -d "$TMPDIR/neuracore/NeuraCore.app" ]; then
        APP_SRC="$TMPDIR/neuracore/NeuraCore.app"
    elif [ -d "$TMPDIR/NeuraCore.app" ]; then
        APP_SRC="$TMPDIR/NeuraCore.app"
    fi
    [ -n "$APP_SRC" ] || fail "Archive does not contain NeuraCore.app."

    say "Installing NeuraCore.app to /Applications ..."
    rm -rf /Applications/NeuraCore.app
    cp -R "$APP_SRC" /Applications/

    say "Clearing quarantine mark ..."
    xattr -dr com.apple.quarantine /Applications/NeuraCore.app 2>/dev/null || true

    say "Linking terminal command to /usr/local/bin/neuracore ..."
    mkdir -p /usr/local/bin
    ln -sf /Applications/NeuraCore.app/Contents/MacOS/neuracore /usr/local/bin/neuracore

    say ""
    say "NeuraCore is installed. Start it from your Applications folder, Launchpad, Spotlight, or run: neuracore"
    say "To upgrade later, run this installer command again."
    exit 0
fi

# Linux package manager detection
if command -v apt-get >/dev/null 2>&1; then
    say "Debian or Ubuntu detected. Adding the NeuraCore repository ..."

    # Which of the two apt repositories this machine belongs to. They are
    # separate roots because an apt suite's Release file names the
    # architectures it serves, so one root per architecture is the only
    # arrangement in which publishing for one cannot break the other. A
    # Raspberry Pi pasting the generic command lands here, and has to be sent
    # to its own root or apt finds the repository and no installable package
    # in it.
    APT_ROOT="apt"
    DPKG_ARCH=$(dpkg --print-architecture 2>/dev/null || echo unknown)
    case "$DPKG_ARCH" in
        arm64) APT_ROOT="apt-arm64" ;;
        amd64) APT_ROOT="apt" ;;
        armhf|armel)
            fail "NeuraCore needs a 64-bit system, and this one is running a 32-bit ($DPKG_ARCH) Debian. On a Raspberry Pi, install the 64-bit Raspberry Pi OS and run this again."
            ;;
        *)
            say "This machine reports the $DPKG_ARCH architecture, which NeuraCore is not published for. Trying the 64-bit x86 repository; see $SITE if apt finds no package."
            ;;
    esac

    mkdir -p /etc/apt/keyrings
    # The armoured key is used directly. apt has read `signed-by` keyrings in
    # this form since 2.4 (Debian 12, Ubuntu 22.04), and it keeps the key out of
    # the deprecated system-wide trusted set, where it would have been trusted
    # for every repository on the machine rather than only this one.
    curl -fsSL "$SITE/neuracore.asc" -o /etc/apt/keyrings/neuracore.asc
    chmod 0644 /etc/apt/keyrings/neuracore.asc
    printf '%s\n' \
        "deb [signed-by=/etc/apt/keyrings/neuracore.asc] $SITE/$APT_ROOT stable main" \
        > /etc/apt/sources.list.d/neuracore.list
    apt-get update
    apt-get install -y neuracore

elif command -v dnf >/dev/null 2>&1; then
    say "Fedora or RHEL detected. Adding the NeuraCore repository ..."
    # `repo_gpgcheck=1` verifies the repository metadata as well as the package.
    # Without it dnf checks only the package signature, and an attacker who could
    # replace the metadata could hide an upgrade rather than forge one.
    cat > /etc/yum.repos.d/neuracore.repo <<REPO
[neuracore]
name=NeuraCore
baseurl=$SITE/rpm
enabled=1
gpgcheck=1
repo_gpgcheck=1
gpgkey=$SITE/neuracore.asc
metadata_expire=300
REPO
    dnf install -y neuracore

elif command -v pacman >/dev/null 2>&1; then
    say "Arch detected. Adding the NeuraCore repository ..."
    curl -fsSL "$SITE/neuracore.asc" -o /tmp/neuracore.asc
    pacman-key --add /tmp/neuracore.asc
    # Locally signing the key is what moves it from "known" to "trusted".
    # Without this step pacman imports the key and then refuses every package
    # signed with it, reporting them as being from an unknown trust source.
    pacman-key --lsign-key "$KEY_FINGERPRINT"
    rm -f /tmp/neuracore.asc
    if ! grep -q '^\[neuracore\]' /etc/pacman.conf; then
        cat >> /etc/pacman.conf <<REPO

[neuracore]
SigLevel = Required DatabaseOptional
Server = $SITE/arch
REPO
    fi
    pacman -Sy --noconfirm neuracore

else
    fail "This system has none of apt, dnf or pacman. See $SITE for the other ways to install NeuraCore."
fi

say ""
say "NeuraCore is installed. Start it from your applications menu, or run: neuracore"
say "It will upgrade with the rest of your system from now on."
