#!/bin/sh
# Gaionix Coder 1.0.0 — POSIX shell syntax; validated macOS Apple Silicon only.
set -eu
umask 077
VERSION=1.0.0
SHA256=5783a0b4c895c57b0c9c0b9ae6358fc7fedde4658dd6b9b277793218ffb9e1fc
URL=https://gaionix.com/downloads/gaionix-coder/1.0.0/gaionix-coder-cli-1.0.0-darwin-arm64.tar.gz
die() { printf 'Gaionix Coder: %s\n' "$*" >&2; exit 1; }
[ "$(uname -s)" = Darwin ] && [ "$(uname -m)" = arm64 ] ||
    die 'Only macOS Apple Silicon (arm64) is supported. No files were installed.'
case ${HOME:-} in /*) ;; *) die 'HOME must be an absolute directory.' ;; esac
for command in curl shasum tar mktemp readlink cmp; do
    command -v "$command" >/dev/null 2>&1 || die "Required command is missing: $command"
done
BIN=$HOME/.local/bin
ROOT=$HOME/.local/share/gaionix-coder
RELEASE=$ROOT/releases/$VERSION-$SHA256
MARKER='gaionix-coder-official-installer-v1'
for directory in "$HOME/.local" "$HOME/.local/bin" "$HOME/.local/share" "$ROOT" "$ROOT/releases"; do
    [ ! -L "$directory" ] || die "Refusing a symlinked installation directory: $directory"
    if [ -e "$directory" ]; then
        [ -d "$directory" ] || die "Not a directory: $directory"
    else
        mkdir "$directory" || die "Cannot create $directory"
    fi
done
if [ -e "$ROOT/.installer" ] || [ -L "$ROOT/.installer" ]; then
    [ ! -L "$ROOT/.installer" ] && [ -f "$ROOT/.installer" ] &&
        [ "$(cat "$ROOT/.installer")" = "$MARKER" ] || die 'Unrecognized installation marker.'
else
    # Never adopt a directory containing an unrelated installation.
    [ -z "$(ls -A "$ROOT/releases")" ] && [ ! -e "$ROOT/current" ] && [ ! -L "$ROOT/current" ] ||
        die 'Existing unrecognized installation; nothing will be replaced.'
    printf '%s\n' "$MARKER" > "$ROOT/.installer"
fi
mkdir "$ROOT/.install-lock" 2>/dev/null || die 'Another installation may be active. Inspect it before removing the install lock.'
STAGE=
CREATED=
ACTIVATED=no
cleanup() {
    status=$?
    trap - 0 HUP INT TERM
    if [ "$ACTIVATED" = no ]; then
        for name in $CREATED; do
            if [ -L "$BIN/$name" ] && [ "$(readlink "$BIN/$name")" = "$ROOT/current/$name" ]; then
                rm "$BIN/$name"
            fi
        done
    fi
    [ -z "$STAGE" ] || rm -rf "$STAGE"
    rmdir "$ROOT/.install-lock"
    exit "$status"
}
trap cleanup 0
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
for name in gaionix-coder gaionix-coder-agent; do
    if [ -e "$BIN/$name" ] || [ -L "$BIN/$name" ]; then
        [ -L "$BIN/$name" ] && [ "$(readlink "$BIN/$name")" = "$ROOT/current/$name" ] ||
            die "Existing unmanaged $BIN/$name preserved. Move it yourself before installing."
    fi
done
if [ -e "$ROOT/current" ] || [ -L "$ROOT/current" ]; then
    [ -L "$ROOT/current" ] || die 'Unmanaged current installation preserved.'
    case $(readlink "$ROOT/current") in "$ROOT"/releases/*) ;; *) die 'Unexpected current installation target.' ;; esac
fi
STAGE=$(mktemp -d "$ROOT/.staging.XXXXXX") || die 'Cannot create private staging directory.'
printf 'Downloading Gaionix Coder %s for macOS Apple Silicon…\n' "$VERSION"
curl --fail --silent --show-error --location --proto '=https' --tlsv1.2 \
    --output "$STAGE/archive.tar.gz" "$URL" || die 'Download failed; existing installation preserved.'
actual=$(shasum -a 256 "$STAGE/archive.tar.gz") || die 'Cannot compute archive SHA-256.'
[ "${actual%% *}" = "$SHA256" ] || die 'SHA-256 mismatch; downloaded code will not be extracted or executed.'
mkdir "$STAGE/payload"
tar -xzf "$STAGE/archive.tar.gz" -C "$STAGE/payload" \
    gaionix-coder gaionix-coder-agent manifest.json README.txt || die 'Cannot extract the verified archive.'
for name in gaionix-coder gaionix-coder-agent manifest.json README.txt; do
    [ -f "$STAGE/payload/$name" ] && [ ! -L "$STAGE/payload/$name" ] || die "Invalid release file: $name"
done
chmod 755 "$STAGE/payload/gaionix-coder" "$STAGE/payload/gaionix-coder-agent"
if [ -e "$RELEASE" ] || [ -L "$RELEASE" ]; then
    [ -d "$RELEASE" ] && [ ! -L "$RELEASE" ] || die 'Existing release path is not a managed directory.'
    for name in gaionix-coder gaionix-coder-agent manifest.json README.txt; do
        [ ! -L "$RELEASE/$name" ] && cmp -s "$STAGE/payload/$name" "$RELEASE/$name" ||
            die 'Existing release contents differ; preserved without overwriting.'
    done
else
    mv "$STAGE/payload" "$RELEASE"
fi
# Only the verified release runs, and only --version. No provider/model request.
printf '\nThis release is ad-hoc signed, without Apple Developer ID signing or notarization.\n'
if output=$("$RELEASE/gaionix-coder" --version 2>&1); then
    printf 'Version check: %s\n' "$output"
else
    printf '%s\n' 'macOS may have blocked the verified executable. The active installation was not changed.' >&2
    printf '%s\n' "Review System Settings → Privacy & Security → Open Anyway for $RELEASE/gaionix-coder, if offered." >&2
    printf '%s\n' 'The sibling runtime may require its own approval. Never bypass a malware/damaged-file warning.' >&2
    die 'See https://gaionix.com/gaionix-coder/docs/troubleshooting/ then rerun this installer.'
fi
for name in gaionix-coder gaionix-coder-agent; do
    if [ ! -L "$BIN/$name" ]; then
        # ln refuses a newly appeared conflicting file; never use ln -f here.
        ln -s "$ROOT/current/$name" "$BIN/$name" || die 'Installation path changed; refusing to overwrite it.'
        CREATED="$CREATED $name"
    fi
done
ln -s "$RELEASE" "$STAGE/current"
# macOS BSD mv -h replaces the symlink itself instead of following its directory.
# Staging is on the same filesystem; one rename switches the matched binary pair.
# Defer cancellation across the rename and its bookkeeping (a few instructions).
trap '' HUP INT TERM
mv -fh "$STAGE/current" "$ROOT/current"
ACTIVATED=yes
trap 'exit 129' HUP
trap 'exit 130' INT
trap 'exit 143' TERM
printf '\nInstalled Gaionix Coder %s into %s\n' "$VERSION" "$BIN"
printf '%s\n' 'Previous managed releases are retained. Shell profiles were not modified.'
case :${PATH:-}: in
    *:"$BIN":*) printf '%s\n' 'PATH already includes ~/.local/bin.' ;;
    *) printf '%s\n' 'For this shell, run: export PATH="$HOME/.local/bin:$PATH"' \
        'To keep it, add that line once to your own shell profile; do not add duplicate entries.' ;;
esac
printf '\nVerify: "%s/gaionix-coder" --version\n' "$BIN"
printf 'Start:  "%s/gaionix-coder" tui --help\n' "$BIN"
printf '%s\n' 'Then open your project, configure your own provider securely, and choose your model.' \
    'No credentials were collected. Starting a model task may incur provider charges.'
