#!/bin/sh
set -eu

fail() {
    printf '%s\n' "gray install: $*" >&2
    exit 1
}

requested_version="${GRAY_VERSION:-}"
requested_prefix="${GRAY_HOME:-}"
modify_path=1
while [ "$#" -gt 0 ]; do
    case "$1" in
        --version)
            [ "$#" -ge 2 ] || fail "missing value after --version"
            requested_version=$2
            shift 2
            ;;
        --prefix)
            [ "$#" -ge 2 ] || fail "missing value after --prefix"
            requested_prefix=$2
            shift 2
            ;;
        --no-modify-path)
            modify_path=0
            shift
            ;;
        --help|-h)
            printf '%s\n' "Usage: install.sh [--version VERSION] [--prefix PATH] [--no-modify-path]"
            exit 0
            ;;
        *) fail "unknown option '$1'" ;;
    esac
done
machine="$(uname -s)-$(uname -m)"
case "$machine" in
    Darwin-arm64|Darwin-aarch64) platform=macos-aarch64 ;;
    Darwin-x86_64)
        if command -v sysctl >/dev/null 2>&1 &&
            [ "$(sysctl -n hw.optional.arm64 2>/dev/null || true)" = 1 ]; then
            platform=macos-aarch64
        else
            fail "unsupported platform '$machine'; expected macOS arm64 or Linux x86-64"
        fi
        ;;
    Linux-x86_64|Linux-amd64) platform=linux-x86_64 ;;
    *) fail "unsupported platform '$machine'; expected macOS arm64 or Linux x86-64" ;;
esac

registry="${GRAY_RELEASE_REGISTRY:-https://archive.graylanguage.com}"
case "$registry" in
    https://*) ;;
    *) fail "GRAY_RELEASE_REGISTRY must use HTTPS" ;;
esac
version="$requested_version"
if [ -z "$version" ]; then
    command -v curl >/dev/null 2>&1 || fail "curl is required"
    version="$(curl --fail --silent --show-error --location \
        --proto '=https' --tlsv1.2 "$registry/v1/releases/latest/$platform")"
fi
printf '%s\n' "$version" | grep -Eq \
    '^[0-9]+\.[0-9]+\.[0-9]+([+-][0-9A-Za-z.-]+)?$' || \
    fail "GRAY_VERSION must be an exact SemVer version"

gray_home="${requested_prefix:-${HOME:?HOME is required}/.gray}"
case "$gray_home" in
    /*) ;;
    *) fail "GRAY_HOME must be an absolute path" ;;
esac

for command in tar awk grep sed mktemp find mkdir mv chmod dirname; do
    command -v "$command" >/dev/null 2>&1 || \
        fail "required command '$command' is unavailable"
done

temporary="$(mktemp -d "${TMPDIR:-/tmp}/gray-install.XXXXXX")"
trap 'rm -rf -- "$temporary"' EXIT HUP INT TERM
archive="$temporary/gray.tar.gz"

if [ -n "${GRAY_INSTALL_ARCHIVE:-}" ]; then
    test -f "$GRAY_INSTALL_ARCHIVE" && test ! -L "$GRAY_INSTALL_ARCHIVE" || \
        fail "GRAY_INSTALL_ARCHIVE is not a regular file"
    cp -- "$GRAY_INSTALL_ARCHIVE" "$archive"
else
    command -v curl >/dev/null 2>&1 || fail "curl is required"
    url="$registry/v1/releases/$version/$platform"
    curl --fail --silent --show-error --location \
        --proto '=https' --tlsv1.2 --output "$archive" "$url"
fi

expected="${GRAY_INSTALL_SHA256:-}"
if [ -z "$expected" ]; then
    command -v curl >/dev/null 2>&1 || fail "curl is required"
    checksum_url="$registry/v1/releases/$version/$platform.sha256"
    expected="$(curl --fail --silent --show-error --location \
        --proto '=https' --tlsv1.2 "$checksum_url" | awk 'NR == 1 {print $1}')"
fi
printf '%s\n' "$expected" | grep -Eq '^[0-9a-f]{64}$' || \
    fail "release checksum is not a lowercase SHA-256 digest"

if command -v sha256sum >/dev/null 2>&1; then
    observed="$(sha256sum "$archive" | awk '{print $1}')"
elif command -v shasum >/dev/null 2>&1; then
    observed="$(shasum -a 256 "$archive" | awk '{print $1}')"
else
    fail "sha256sum or shasum is required"
fi
[ "$observed" = "$expected" ] || fail "archive SHA-256 mismatch"

listing="$temporary/listing"
tar -tzf "$archive" >"$listing" || fail "cannot read release archive"
top="$(awk -F/ '
    BEGIN { top = "" }
    /^\// { exit 2 }
    {
        if ($1 == "" || $1 == "." || $1 == "..") exit 2
        for (i = 1; i <= NF; i++) if ($i == "..") exit 2
        if (top == "") top = $1
        if ($1 != top) exit 3
    }
    END { if (top == "") exit 4; print top }
' "$listing")" || fail "archive paths are unsafe or have multiple roots"

extracted="$temporary/extracted"
mkdir -p "$extracted"
tar -xzf "$archive" -C "$extracted" || fail "cannot extract release archive"
bundle="$extracted/$top"
test -d "$bundle" && test ! -L "$bundle" || fail "invalid bundle root"
if find "$bundle" -type l -o ! -type d ! -type f | grep -q .; then
    fail "bundle contains links or unsupported file types"
fi
test -x "$bundle/bin/gray" || fail "bundle has no Gray executable"

versions="$gray_home/versions"
target="$versions/$version/$platform"
mkdir -p "$versions/$version" "$gray_home/bin"
if [ -e "$target" ] || [ -L "$target" ]; then
    fail "Gray $version for $platform is already installed"
fi
mv "$bundle" "$target"

shim_tmp="$gray_home/bin/.gray.tmp.$$"
cat >"$shim_tmp" <<'SHIM'
#!/bin/sh
set -eu
gray_home="${GRAY_HOME:-${HOME:?HOME is required}/.gray}"
platform='@PLATFORM@'
source=user-default
if [ -n "${GRAY_VERSION:-}" ]; then
    version="$GRAY_VERSION"
    source=GRAY_VERSION
else
    current="$(pwd -P)"
    version=""
    while :; do
        if [ -f "$current/.gray-version" ] && [ ! -L "$current/.gray-version" ]; then
            version="$(sed -n '1p' "$current/.gray-version")"
            source="$current/.gray-version"
            break
        fi
        parent="$(dirname "$current")"
        [ "$parent" = "$current" ] && break
        current="$parent"
    done
    if [ -z "$version" ]; then
        config="$gray_home/config.json"
        [ -f "$config" ] && [ ! -L "$config" ] || {
            printf '%s\n' "gray: no version selected; run 'gray version use <version>'" >&2
            exit 1
        }
        version="$(sed -n 's/^{"default_version":"\([^"]*\)"}$/\1/p' "$config")"
    fi
fi
printf '%s\n' "$version" | grep -Eq '^[0-9]+\.[0-9]+\.[0-9]+([+-][0-9A-Za-z.-]+)?$' || {
    printf '%s\n' "gray: selected version is not exact SemVer" >&2
    exit 1
}
binary="$gray_home/versions/$version/$platform/bin/gray"
[ -x "$binary" ] && [ ! -L "$binary" ] || {
    printf '%s\n' "gray: selected Gray $version is not installed for $platform" >&2
    exit 1
}
export GRAY_SHIM_VERSION="$version" GRAY_SHIM_SOURCE="$source"
exec "$binary" "$@"
SHIM
awk -v platform="$platform" \
    '{gsub(/@PLATFORM@/, platform); print}' "$shim_tmp" >"$shim_tmp.rendered"
mv "$shim_tmp.rendered" "$shim_tmp"
chmod 0755 "$shim_tmp"

config_tmp="$gray_home/.config.tmp.$$"
printf '{"default_version":"%s"}\n' "$version" >"$config_tmp"
chmod 0600 "$config_tmp"
mv "$config_tmp" "$gray_home/config.json"
mv "$shim_tmp" "$gray_home/bin/gray"

GRAY_HOME="$gray_home" "$gray_home/bin/gray" doctor --first-install || \
    fail "installed Gray failed first-install diagnostics"

printf '%s\n' "Installed Gray $version for $platform in $gray_home"
if [ "$modify_path" -eq 1 ]; then
    : "${HOME:?HOME is required to configure PATH}"
    shell_name=${SHELL##*/}
    case "$shell_name" in
        zsh)
            profile_root=${ZDOTDIR:-$HOME}
            case "$profile_root" in
                /*) ;;
                *) profile_root="$HOME/$profile_root" ;;
            esac
            profile="$profile_root/.zshrc"
            ;;
        bash)
            case "$platform" in
                macos-*) profile="$HOME/.bash_profile" ;;
                *) profile="$HOME/.bashrc" ;;
            esac
            ;;
        fish)
            profile_root=${XDG_CONFIG_HOME:-$HOME/.config}
            case "$profile_root" in
                /*) ;;
                *) profile_root="$HOME/$profile_root" ;;
            esac
            profile="$profile_root/fish/config.fish"
            ;;
        *) profile="$HOME/.profile" ;;
    esac
    mkdir -p "$(dirname "$profile")"
    if [ "$shell_name" = fish ]; then
        quoted_home="$(printf '%s' "$gray_home" | sed "s/'/\\\\'/g")"
        path_line="set -gx GRAY_HOME '$quoted_home'; fish_add_path --prepend \"\$GRAY_HOME/bin\" # Gray"
    else
        quoted_home="$(printf '%s' "$gray_home" | sed "s/'/'\\\\''/g")"
        path_line="export GRAY_HOME='$quoted_home'; export PATH=\"\$GRAY_HOME/bin:\$PATH\" # Gray"
    fi
    if [ ! -f "$profile" ] || ! grep -Fqx "$path_line" "$profile"; then
        printf '\n%s\n' "$path_line" >>"$profile"
    fi
    printf '%s\n' "Configured $gray_home/bin in $profile; open a new shell to use gray."
fi
