#!/bin/sh
# install.sh -- Cross-platform installer for the Weave CLI
#
# Usage:
#   curl -fsSL https://get.weave.build | sh
#
# Environment variables:
#   WEAVE_VERSION         Version to install (default: "latest")
#   WEAVE_INSTALL_DIR     Installation directory (default: ~/.local/bin)
#   WEAVE_BASE_URL        Base URL for binary downloads
#   WEAVE_NO_MODIFY_PATH  Set to 1 to skip PATH modification
#   WEAVE_USER            HTTP Basic Auth username. Pair with WEAVE_PASSWORD.
#                         Only needed for auth-required repos; the default
#                         public release repo serves anonymously.
#   WEAVE_PASSWORD        HTTP Basic Auth password. Required if WEAVE_USER
#                         is set; both or neither.

set -eu

# ---------------------------------------------------------------------------
# Output helpers
# ---------------------------------------------------------------------------

if [ -t 1 ]; then
    BOLD='\033[1m'
    GREEN='\033[0;32m'
    YELLOW='\033[0;33m'
    RED='\033[0;31m'
    RESET='\033[0m'
else
    BOLD='' GREEN='' YELLOW='' RED='' RESET=''
fi

info() { printf "${GREEN}info:${RESET} %s\n" "$1"; }
warn() { printf "${YELLOW}warn:${RESET} %s\n" "$1" >&2; }
err()  { printf "${RED}error:${RESET} %s\n" "$1" >&2; }
die()  { err "$1"; exit 1; }

# ---------------------------------------------------------------------------
# Platform detection
# ---------------------------------------------------------------------------

detect_platform() {
    OS="$(uname -s)"
    ARCH="$(uname -m)"

    case "$OS" in
        Linux)                PLATFORM="linux" ;;
        Darwin)               PLATFORM="darwin" ;;
        MINGW*|MSYS*|CYGWIN*) PLATFORM="windows" ;;
        *)                    die "Unsupported operating system: $OS" ;;
    esac

    case "$ARCH" in
        x86_64|amd64)   ARCH="x86_64" ;;
        aarch64|arm64)  ARCH="aarch64" ;;
        *)              die "Unsupported architecture: $ARCH" ;;
    esac

    # macOS uses a universal (fat) binary covering both Intel and Apple Silicon
    if [ "$PLATFORM" = "darwin" ]; then
        BINARY_NAME="weave-darwin-universal"
    elif [ "$PLATFORM" = "windows" ]; then
        if [ "$ARCH" != "x86_64" ]; then
            die "Windows builds are only available for x86_64"
        fi
        BINARY_NAME="weave-windows-x86_64.exe"
    else
        BINARY_NAME="weave-${PLATFORM}-${ARCH}"
    fi
}

# ---------------------------------------------------------------------------
# Tool detection
# ---------------------------------------------------------------------------

detect_downloader() {
    if command -v curl >/dev/null 2>&1; then
        DOWNLOADER="curl"
    elif command -v wget >/dev/null 2>&1; then
        DOWNLOADER="wget"
    else
        die "Either 'curl' or 'wget' is required but neither was found"
    fi
}

validate_auth_env() {
    # Fail fast if only one of WEAVE_USER / WEAVE_PASSWORD is set.
    # Silently dropping to no-auth because one half was forgotten is
    # the kind of mistake you only catch in production.
    if [ -n "${WEAVE_USER:-}" ] && [ -z "${WEAVE_PASSWORD:-}" ]; then
        die "WEAVE_USER is set but WEAVE_PASSWORD is empty. Set both or neither."
    fi
    if [ -z "${WEAVE_USER:-}" ] && [ -n "${WEAVE_PASSWORD:-}" ]; then
        die "WEAVE_PASSWORD is set but WEAVE_USER is empty. Set both or neither."
    fi
}

download() {
    # Download a URL to a file. Args: $1=url $2=output_path
    # Auth: WEAVE_USER + WEAVE_PASSWORD → HTTP Basic; otherwise anonymous.
    if [ -n "${WEAVE_USER:-}" ]; then
        if [ "$DOWNLOADER" = "curl" ]; then
            curl -fsSL --retry 3 --retry-delay 2 --user "${WEAVE_USER}:${WEAVE_PASSWORD}" -o "$2" "$1"
        else
            wget -q --tries=3 --user="${WEAVE_USER}" --password="${WEAVE_PASSWORD}" -O "$2" "$1"
        fi
    else
        if [ "$DOWNLOADER" = "curl" ]; then
            curl -fsSL --retry 3 --retry-delay 2 -o "$2" "$1"
        else
            wget -q --tries=3 -O "$2" "$1"
        fi
    fi
}

download_to_stdout() {
    # Download a URL and print to stdout. Args: $1=url
    if [ -n "${WEAVE_USER:-}" ]; then
        if [ "$DOWNLOADER" = "curl" ]; then
            curl -fsSL --retry 3 --retry-delay 2 --user "${WEAVE_USER}:${WEAVE_PASSWORD}" "$1"
        else
            wget -q --tries=3 --user="${WEAVE_USER}" --password="${WEAVE_PASSWORD}" -O - "$1"
        fi
    else
        if [ "$DOWNLOADER" = "curl" ]; then
            curl -fsSL --retry 3 --retry-delay 2 "$1"
        else
            wget -q --tries=3 -O - "$1"
        fi
    fi
}

detect_checksum_tool() {
    if command -v sha256sum >/dev/null 2>&1; then
        CHECKSUM_TOOL="sha256sum"
    elif command -v shasum >/dev/null 2>&1; then
        CHECKSUM_TOOL="shasum"
    else
        die "Either 'sha256sum' or 'shasum' is required for checksum verification"
    fi
}

verify_checksum() {
    # Verify SHA-256 checksum. Args: $1=file_path $2=expected_hash
    if [ "$CHECKSUM_TOOL" = "sha256sum" ]; then
        ACTUAL_HASH="$(sha256sum "$1" | cut -d' ' -f1)"
    else
        ACTUAL_HASH="$(shasum -a 256 "$1" | cut -d' ' -f1)"
    fi

    if [ "$ACTUAL_HASH" != "$2" ]; then
        die "Checksum verification failed!
  Expected: $2
  Got:      $ACTUAL_HASH

This could indicate a corrupted download or a tampered binary."
    fi
}

# ---------------------------------------------------------------------------
# Version resolution
# ---------------------------------------------------------------------------

resolve_version() {
    VERSION="${WEAVE_VERSION:-latest}"

    if [ "$VERSION" = "latest" ]; then
        info "Resolving latest version..."
        LATEST_URL="${BASE_URL%/}/latest-version"
        VERSION="$(download_to_stdout "$LATEST_URL")" || \
            die "Failed to resolve latest version. Set WEAVE_VERSION explicitly (e.g., WEAVE_VERSION=0.1.0)"
        VERSION="$(printf '%s' "$VERSION" | tr -d '[:space:]')"
        if [ -z "$VERSION" ]; then
            die "Could not determine latest version. Set WEAVE_VERSION explicitly."
        fi
    fi

    # Strip leading 'v' if present
    VERSION="${VERSION#v}"

    info "Installing weave v${VERSION}"
}

# ---------------------------------------------------------------------------
# Installation
# ---------------------------------------------------------------------------

setup_install_dir() {
    INSTALL_DIR="${WEAVE_INSTALL_DIR:-${HOME}/.local/bin}"

    if [ ! -d "$INSTALL_DIR" ]; then
        info "Creating installation directory: $INSTALL_DIR"
        mkdir -p "$INSTALL_DIR" || die "Failed to create directory: $INSTALL_DIR"
    fi

    if [ ! -w "$INSTALL_DIR" ]; then
        die "Installation directory is not writable: $INSTALL_DIR
  Try: WEAVE_INSTALL_DIR=/some/writable/path curl -fsSL <url> | sh"
    fi
}

do_install() {
    DOWNLOAD_URL="${BASE_URL%/}/v${VERSION}/${BINARY_NAME}"
    CHECKSUM_URL="${DOWNLOAD_URL}.sha256"

    TMP_DIR="$(mktemp -d)" || die "Failed to create temporary directory"
    trap 'rm -rf "$TMP_DIR"' EXIT INT TERM

    TMP_BINARY="${TMP_DIR}/${BINARY_NAME}"
    TMP_CHECKSUM="${TMP_DIR}/${BINARY_NAME}.sha256"

    info "Downloading weave v${VERSION} for ${PLATFORM}/${ARCH}..."
    download "$DOWNLOAD_URL" "$TMP_BINARY" || \
        die "Failed to download binary from: $DOWNLOAD_URL
  If the registry requires auth, set WEAVE_USER + WEAVE_PASSWORD."

    info "Verifying checksum..."
    download "$CHECKSUM_URL" "$TMP_CHECKSUM" || \
        die "Failed to download checksum file from: $CHECKSUM_URL"

    EXPECTED_HASH="$(cut -d' ' -f1 < "$TMP_CHECKSUM")"
    verify_checksum "$TMP_BINARY" "$EXPECTED_HASH"
    info "Checksum verified"

    TARGET_BINARY="${INSTALL_DIR}/weave"
    if [ "$PLATFORM" = "windows" ]; then
        TARGET_BINARY="${INSTALL_DIR}/weave.exe"
    fi

    # Atomic install: copy to temp in target dir, then rename
    TMP_TARGET="${INSTALL_DIR}/.weave.tmp.$$"
    cp "$TMP_BINARY" "$TMP_TARGET"
    chmod +x "$TMP_TARGET"
    mv "$TMP_TARGET" "$TARGET_BINARY"

    info "Installed weave to: $TARGET_BINARY"
}

# ---------------------------------------------------------------------------
# PATH setup
# ---------------------------------------------------------------------------

ensure_in_path() {
    if [ "${WEAVE_NO_MODIFY_PATH:-0}" = "1" ]; then
        return
    fi

    # Check if install dir is already in PATH
    case ":${PATH}:" in
        *":${INSTALL_DIR}:"*) return ;;
    esac

    SHELL_NAME="$(basename "${SHELL:-/bin/sh}")"
    RC_FILE=""

    case "$SHELL_NAME" in
        bash)
            # macOS bash uses .bash_profile for login shells (Terminal.app),
            # Linux bash uses .bashrc for interactive non-login shells.
            if [ "$PLATFORM" = "darwin" ]; then
                RC_FILE="${HOME}/.bash_profile"
            elif [ -f "${HOME}/.bashrc" ]; then
                RC_FILE="${HOME}/.bashrc"
            elif [ -f "${HOME}/.bash_profile" ]; then
                RC_FILE="${HOME}/.bash_profile"
            else
                RC_FILE="${HOME}/.bashrc"
            fi
            ;;
        zsh)
            # .zshrc is sourced for interactive shells on both macOS and Linux.
            # macOS Terminal.app starts login shells, but zsh sources .zshrc
            # for all interactive shells regardless of login status.
            RC_FILE="${HOME}/.zshrc"
            ;;
        fish)
            RC_FILE="${HOME}/.config/fish/config.fish"
            ;;
        *)
            RC_FILE="${HOME}/.profile"
            ;;
    esac

    PATH_LINE="export PATH=\"${INSTALL_DIR}:\$PATH\""
    if [ "$SHELL_NAME" = "fish" ]; then
        PATH_LINE="fish_add_path ${INSTALL_DIR}"
    fi

    # Idempotent: check if already present
    if [ -f "$RC_FILE" ] && grep -qF "$INSTALL_DIR" "$RC_FILE" 2>/dev/null; then
        return
    fi

    printf '\n# Added by weave installer\n%s\n' "$PATH_LINE" >> "$RC_FILE"
    warn "Added ${INSTALL_DIR} to PATH in ${RC_FILE}"
    NEED_RELOAD=1
}

# ---------------------------------------------------------------------------
# Success message
# ---------------------------------------------------------------------------

print_success() {
    printf "\n"
    printf '%s%sWeave v%s installed successfully!%s\n' "$GREEN" "$BOLD" "$VERSION" "$RESET"
    printf "\n"
    printf '  %sBinary:%s  %s\n' "$BOLD" "$RESET" "$TARGET_BINARY"
    printf '  %sConfig:%s  ~/.config/weave/\n' "$BOLD" "$RESET"
    printf '  %sData:%s    ~/.local/share/weave/\n' "$BOLD" "$RESET"
    printf "\n"

    if [ "${NEED_RELOAD:-0}" = "1" ]; then
        printf '  %sRestart your shell or run:%s\n' "$YELLOW" "$RESET"
        printf "    source %s\n" "$RC_FILE"
        printf "\n"
    fi

    printf '  %sGet started:%s\n' "$BOLD" "$RESET"
    printf "    weave --help\n"
    printf "\n"
    printf '  %sTo uninstall:%s\n' "$BOLD" "$RESET"
    printf "    rm %s\n" "$TARGET_BINARY"
    printf "    # Optionally remove config and data:\n"
    printf "    # rm -rf ~/.config/weave ~/.local/share/weave\n"
}

# ---------------------------------------------------------------------------
# Main
# ---------------------------------------------------------------------------

main() {
    BASE_URL="${WEAVE_BASE_URL:-https://dl.weave.build/releases}"
    NEED_RELOAD=0

    validate_auth_env
    detect_platform
    detect_downloader
    detect_checksum_tool
    resolve_version
    setup_install_dir
    do_install
    ensure_in_path
    print_success
}

main "$@"
