#!/bin/sh

# cmdop CLI Installer
# Downloads and installs the cmdop command-line tool
#
# Canonical entry (install.cmdop.com PROXIES this script body — always latest):
#   curl -fsSL https://install.cmdop.com | sh
#
# Custom installation directory:
#   curl -fsSL https://install.cmdop.com | sh -s -- --prefix=$HOME/.local/bin
#
# Binaries download from Cloudflare R2 via install.cmdop.com/cli/latest/<asset>
# (the storage of record). The worker resolves "latest" from the R2 update
# manifest and redirects to one immutable versioned object. The installer
# verifies the downloaded bytes against that release's SHA256SUMS before install.

set -e

# Helper function to check if command exists
command_exists() {
    command -v "$1" >/dev/null 2>&1
}

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

BINARY_NAME="cmdop"
# Download base: install.cmdop.com/cli/latest/<asset> — the worker resolves
# the current version from the R2 manifest and streams the object. No GitHub.
BASE_URL="https://install.cmdop.com/cli/latest"

# Default installation prefix
INSTALL_PREFIX="/usr/local/bin"

# Non-interactive knobs (also settable via env, so a .pkg postinstall can drive
# this same script as the ONE source of truth — see release/cli/macos/scripts):
#   --quiet / CMDOP_QUIET=1  suppress banner + PATH hints (mechanical run).
QUIET="${CMDOP_QUIET:-0}"
TEST_MODE="${CMDOP_INSTALLER_TEST_MODE:-0}"

print_line() {
    printf '%b\n' "$1"
}

# Parse arguments
while [ "$#" -gt 0 ]; do
    case $1 in
        --prefix)
            INSTALL_PREFIX="$2"
            shift 2
            ;;
        --prefix=*)
            INSTALL_PREFIX="${1#*=}"
            shift
            ;;
        --quiet)
            QUIET=1
            shift
            ;;
        *)
            echo "Unknown option: $1"
            exit 1
            ;;
    esac
done

# ASCII Banner (skipped in --quiet mode, e.g. a .pkg postinstall)
if [ "$QUIET" != "1" ]; then
print_line "${BLUE}"
cat << 'BANNER'
 ██████╗███╗   ███╗██████╗  ██████╗ ██████╗
██╔════╝████╗ ████║██╔══██╗██╔═══██╗██╔══██╗
██║     ██╔████╔██║██║  ██║██║   ██║██████╔╝
██║     ██║╚██╔╝██║██║  ██║██║   ██║██╔═══╝
╚██████╗██║ ╚═╝ ██║██████╔╝╚██████╔╝██║
 ╚═════╝╚═╝     ╚═╝╚═════╝  ╚═════╝ ╚═╝
BANNER
print_line "${NC}"
fi

# Detect OS and Arch
OS="$(uname -s)"
ARCH="$(uname -m)"

case "${OS}" in
    Linux*)     OS=linux;;
    Darwin*)    OS=darwin;;
    *)
        print_line "${RED}❌ Unsupported OS: ${OS}${NC}"
        echo "   Supported: Linux, macOS"
        exit 1
        ;;
esac

case "${ARCH}" in
    x86_64)    ARCH=x64;;
    arm64)     ARCH=arm64;;
    aarch64)   ARCH=arm64;;
    *)
        print_line "${RED}❌ Unsupported Architecture: ${ARCH}${NC}"
        echo "   Supported: x64, arm64"
        exit 1
        ;;
esac

# Map OS/ARCH to release file names
case "${OS}/${ARCH}" in
    linux/x64)    PLATFORM_LABEL="linux-x64";;
    linux/arm64)  PLATFORM_LABEL="linux-arm64";;
    darwin/x64)   PLATFORM_LABEL="macos-intel";;
    darwin/arm64) PLATFORM_LABEL="macos-silicon";;
esac

# The native config path must match utils.Paths(). A process invoked as root
# installs only the binary: it never traverses a user-controlled home, writes
# user config, or guesses a GUI/session identity. Binary-copy sudo from a normal
# invocation does not change this process identity, so that path still returns
# here as the invoking user and can safely configure its own account.
CONFIG_ENABLED=true
if [ "$(id -u)" = "0" ]; then
    CONFIG_ENABLED=false
    CONFIG_DIR=""
    CONFIG_FILE=""
else
    TARGET_HOME="$HOME"
    if [ "$OS" = "darwin" ]; then
        CONFIG_DIR="$TARGET_HOME/Library/Application Support/cmdop"
    else
        CONFIG_DIR="${XDG_CONFIG_HOME:-$TARGET_HOME/.config}/cmdop"
    fi
    CONFIG_FILE="$CONFIG_DIR/config.yaml"
fi

# Test mode is intentionally before download/sudo/config mutation. It exists
# solely for the repository's shell portability checks.
if [ "$TEST_MODE" = "1" ]; then
    printf 'os=%s\nconfig_enabled=%s\nconfig_dir=%s\n' "$OS" "$CONFIG_ENABLED" "$CONFIG_DIR"
    exit 0
fi

print_line "${BLUE}💻 Detected: $OS/$ARCH${NC}"

# Construct Download URL
BINARY_FILE="$BINARY_NAME-$PLATFORM_LABEL"
DOWNLOAD_URL="$BASE_URL/$BINARY_FILE"
CHECKSUMS_URL="$BASE_URL/SHA256SUMS"

print_line "${BLUE}⬇️  Downloading cmdop...${NC}"

# Create temp directory in a safe location
# This works regardless of current directory (even if it's read-only like /)
if [ -n "$TMPDIR" ]; then
    # macOS/BSD sets TMPDIR
    TMP_BASE="$TMPDIR"
elif [ -d "/tmp" ] && [ -w "/tmp" ]; then
    # Linux/Unix standard
    TMP_BASE="/tmp"
else
    # Fallback to home directory
    TMP_BASE="$HOME"
fi

TMP_DIR=$(mktemp -d "${TMP_BASE}/cmdop-install.XXXXXX" 2>/dev/null || mktemp -d)
cleanup() {
    rm -rf "$TMP_DIR"
}
trap cleanup 0

# Verify temp directory is writable
if [ ! -w "$TMP_DIR" ]; then
    print_line "${RED}❌ Cannot create writable temporary directory${NC}"
    echo ""
    echo "💡 Try running from your home directory:"
    echo "   cd ~"
    echo "   curl -fsSL https://install.cmdop.com | sh"
    exit 1
fi

BINARY_PATH="$TMP_DIR/$BINARY_NAME"

# Download with animated spinner
download_with_spinner() {
    url=$1
    output=$2

    # Start download in background
    curl -fL "$url" -o "$output" 2>/dev/null &
    pid=$!

    # Show spinner while downloading
    while kill -0 $pid 2>/dev/null; do
        printf "." >&2
        sleep 0.1
    done

    wait $pid
    exit_code=$?

    if [ $exit_code -eq 0 ]; then
        # Show success with file size
        size_mb=$(ls -l "$output" 2>/dev/null | awk '{printf "%.1f", $5/1048576}')
        printf "\r   ${GREEN}✓${NC} Downloaded (${size_mb} MB)                    \n" >&2
    fi

    return $exit_code
}

if command_exists curl; then
    download_with_spinner "$DOWNLOAD_URL" "$BINARY_PATH" || {
        CURL_EXIT=$?
        echo ""
        print_line "${RED}❌ Failed to download cmdop${NC}"
        echo ""
        if [ $CURL_EXIT -eq 56 ]; then
            echo "💡 Network error (timeout or connection issue)"
            echo "   Please check your internet connection and try again"
        else
            echo "💡 Try downloading manually:"
            echo "   curl -L $DOWNLOAD_URL -o cmdop && chmod +x cmdop && sudo mv cmdop /usr/local/bin/"
        fi
        exit 1
    }
elif command_exists wget; then
    # wget fallback with spinner
    wget -q "$DOWNLOAD_URL" -O "$BINARY_PATH" &
    pid=$!
    while kill -0 $pid 2>/dev/null; do
        printf "."
        sleep 0.1
    done
    wait $pid || {
        echo ""
        print_line "${RED}❌ Failed to download cmdop${NC}"
        exit 1
    }
    size_mb=$(ls -l "$BINARY_PATH" 2>/dev/null | awk '{printf "%.1f", $5/1048576}')
    printf "\r   ${GREEN}✓${NC} Downloaded (${size_mb} MB)                    \n"
else
    print_line "${RED}❌ Error: curl or wget is required${NC}"
    exit 1
fi

# Verify before chmod/move. `latest` redirects both requests to immutable keys;
# if a release lands between them, the mismatch fails closed and a retry gets a
# consistent pair. Never install bytes that were not advertised by the release.
CHECKSUMS_PATH="$TMP_DIR/SHA256SUMS"
if command_exists curl; then
    curl -fsSL "$CHECKSUMS_URL" -o "$CHECKSUMS_PATH"
else
    wget -q "$CHECKSUMS_URL" -O "$CHECKSUMS_PATH"
fi

EXPECTED_SHA=$(awk -v file="$BINARY_FILE" '
    ($2 == file || $2 == "*" file) && $1 ~ /^[0-9A-Fa-f]+$/ && length($1) == 64 {
        print tolower($1); exit
    }
' "$CHECKSUMS_PATH")
if [ -z "$EXPECTED_SHA" ]; then
    print_line "${RED}❌ SHA256SUMS has no valid entry for $BINARY_FILE${NC}"
    exit 1
fi

if command_exists sha256sum; then
    ACTUAL_SHA=$(sha256sum "$BINARY_PATH" | awk '{print tolower($1)}')
elif command_exists shasum; then
    ACTUAL_SHA=$(shasum -a 256 "$BINARY_PATH" | awk '{print tolower($1)}')
else
    print_line "${RED}❌ sha256sum or shasum is required to verify cmdop${NC}"
    exit 1
fi

if [ "$ACTUAL_SHA" != "$EXPECTED_SHA" ]; then
    print_line "${RED}❌ cmdop SHA256 verification failed${NC}"
    echo "   expected: $EXPECTED_SHA"
    echo "   received: $ACTUAL_SHA"
    exit 1
fi
print_line "${GREEN}✅ SHA256 verified${NC}"

# Make binary executable
chmod +x "$BINARY_PATH"

# Install binary
print_line "${BLUE}📦 Installing to: $INSTALL_PREFIX/$BINARY_NAME${NC}"

# Check if we need sudo
NEED_SUDO=false
if [ ! -w "$INSTALL_PREFIX" ]; then
    NEED_SUDO=true
fi

if [ "$NEED_SUDO" = true ]; then
    if command_exists sudo; then
        sudo mkdir -p "$INSTALL_PREFIX"
        sudo mv "$BINARY_PATH" "$INSTALL_PREFIX/$BINARY_NAME"
        sudo chmod +x "$INSTALL_PREFIX/$BINARY_NAME"
    else
        print_line "${RED}❌ Installation requires sudo, but sudo is not available${NC}"
        echo ""
        echo "💡 Try installing to a user directory:"
        echo "   curl -fsSL https://install.cmdop.com | sh -s -- --prefix=\$HOME/.local/bin"
        exit 1
    fi
else
    mkdir -p "$INSTALL_PREFIX"
    mv "$BINARY_PATH" "$INSTALL_PREFIX/$BINARY_NAME"
fi

echo ""
print_line "${GREEN}✅ cmdop CLI installed successfully!${NC}"
echo ""

# Create only a native, private configuration for a validated interactive user.
if [ "$CONFIG_ENABLED" = true ] && [ ! -f "$CONFIG_FILE" ]; then
    print_line "${BLUE}⚙️  Creating default configuration...${NC}"
    (umask 077 && mkdir -p -m 700 "$CONFIG_DIR")

    cat > "$CONFIG_FILE" << 'EOF'
# cmdop CLI Configuration
mode: prod
log_level: warn
log_format: console

servers:
  dev:
    host: localhost
    port: 63142
    http_host: localhost
    http_port: 63141
    use_tls: false
  prod:
    host: grpc.cmdop.com
    port: 443
    http_host: api.cmdop.com
    http_port: 443
    use_tls: true
EOF

    chmod 600 "$CONFIG_FILE"

    print_line "${GREEN}✅ Configuration created at: $CONFIG_FILE${NC}"
    echo ""
fi

# Repair private modes only in the invoking user's own unprivileged context.
if [ "$CONFIG_ENABLED" = true ] && [ -f "$CONFIG_FILE" ]; then
    chmod 700 "$CONFIG_DIR"
    chmod 600 "$CONFIG_FILE"
fi

# Setup the default interactive user service for auto-start. Binary-copy sudo
# is deliberately not reused here: a root daemon cannot access the user's
# Keychain, notifications, or cmdop:// session. `--system` remains an explicit
# administrator operation outside this installer.
setup_service() {
    SERVICE_UNIT_INSTALLED=false
    SERVICE_STARTED=false

    if [ "$CONFIG_ENABLED" != true ]; then
        print_line "${YELLOW}⚠️  Root install is binary-only; no user service was created${NC}"
        print_line "   Sign in as the target user, then run: cmdop service install"
        return 0
    fi

    print_line "${BLUE}⚙️  Setting up service unit for $(id -un)...${NC}"
    if "$CMDOP_BIN" service install 2>/dev/null; then
        SERVICE_UNIT_INSTALLED=true
        print_line "${GREEN}✅ User service unit installed and auto-start enabled${NC}"
        if "$CMDOP_BIN" service start 2>/dev/null; then
            SERVICE_STARTED=true
            print_line "   Agent started in the current user session"
        else
            print_line "   Agent was not started now; the unit remains installed for the next login/boot"
        fi
    else
        print_line "${YELLOW}⚠️  Could not install user service${NC}"
        print_line "   You can manually install later: cmdop service install"
    fi
}

# Resolve the installed binary explicitly (a root .pkg postinstall may not have
# $INSTALL_PREFIX on PATH; prefer the exact path we just installed to).
CMDOP_BIN="$INSTALL_PREFIX/$BINARY_NAME"
if [ ! -x "$CMDOP_BIN" ] && command_exists cmdop; then
    CMDOP_BIN="$(command -v cmdop)"
fi

# Verify installation and show quick start
if [ -x "$CMDOP_BIN" ]; then
    # Get installed version
    INSTALLED_VERSION=$("$CMDOP_BIN" version 2>/dev/null | head -1 | sed 's/CMDOP CLI version //' || echo "unknown")

    # Setup a current-user service for auto-start (Linux/macOS)
    setup_service

    if [ "$QUIET" != "1" ]; then
        print_line "${GREEN}🎉 cmdop v${INSTALLED_VERSION} installed successfully!${NC}"
        echo ""
        print_line "${BLUE}🚀 Get Started:${NC}"
        echo ""
        print_line "   ${GREEN}cmdop${NC}         Open the web console for this machine"
        print_line "   ${GREEN}cmdop chat${NC}    AI agent in the terminal (guided setup on first run)"
        echo ""
        print_line "   Joining an existing cmdop server instead?"
        print_line "   ${GREEN}cmdop enroll <enrollment-password> --server <url>${NC}"
        echo ""
        if [ "$SERVICE_STARTED" = true ]; then
            print_line "   The user service unit is installed and the agent was started."
        elif [ "$SERVICE_UNIT_INSTALLED" = true ]; then
            print_line "   The user service unit is installed but was not started now."
        else
            print_line "   No user service unit was installed."
            print_line "   Sign in as the target user and run: cmdop service install"
        fi
        echo ""
    fi
elif [ "$QUIET" != "1" ]; then
    print_line "${YELLOW}⚠️  cmdop was installed but is not in your PATH${NC}"
    echo ""
    echo "Add $INSTALL_PREFIX to your PATH:"

    SHELL_NAME=$(basename "$SHELL")
    case "$SHELL_NAME" in
        bash)
            echo "  echo 'export PATH=\"$INSTALL_PREFIX:\$PATH\"' >> ~/.bashrc"
            echo "  source ~/.bashrc"
            ;;
        zsh)
            echo "  echo 'export PATH=\"$INSTALL_PREFIX:\$PATH\"' >> ~/.zshrc"
            echo "  source ~/.zshrc"
            ;;
        *)
            echo "  export PATH=\"$INSTALL_PREFIX:\$PATH\""
            ;;
    esac
fi

echo ""
