#!/usr/bin/env bash
# Artemis CLI Installer
# Downloads and installs artemis-cli for the current platform
#
# Usage:
#   curl -L \
#     "https://files.artemis.turintech.ai/public/artemis-cli/latest/artemis-cli-installer.sh" \
#     -o installer.sh && chmod +x installer.sh && ./installer.sh
#
# Or with version selection:
#   ./installer.sh                    # Newest stable release (default)
#   ./installer.sh --version 1.2.0    # Specific release
#   ./installer.sh --nightly          # Newest release incl. prereleases
#   ./installer.sh --dev              # Rolling development build
#
# Or with deployment selection. Without one the installer leaves the
# configuration alone and tells you to run `artemis login --url <url>`:
#   ./installer.sh --env dev --allow-insecure-http           # Dev deployment (plain HTTP)
#   ./installer.sh --env testing                             # Testing deployment
#   ./installer.sh --base-url https://artemis.internal       # Custom deployment
#   ./installer.sh --env dev --reset-config                  # ... and drop per-service URLs
#
# Behind an internal certificate authority, or with no route to our file server:
#   ./installer.sh --base-url https://artemis.internal --ca-cert /etc/pki/ca.pem
#   ./installer.sh --download-url https://mirror.internal/artemis-cli
#   ./installer.sh --from-file ./artemis-cli-linux-amd64 --checksum <sha256>

set -e

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

# Where the builds are downloaded from. Not the deployment the CLI is pointed
# at - that is $ENV.
DOWNLOAD_ROOT="https://files.artemis.turintech.ai/public/artemis-cli"
BINARY_NAME="artemis"

# Default install directory - use ~/.local/bin (no sudo needed)
DEFAULT_INSTALL_DIR="$HOME/.local/bin"
INSTALL_DIR=""

# Version selection: empty = newest stable release
VERSION=""
DEV=false
NIGHTLY=false

# Deployment the CLI gets pointed at (named environment or full URL). Empty
# means the user did not choose one, and the configuration is left alone:
# defaulting to our production deployment silently pointed `--dev` installs,
# and every customer install, at the wrong place (ART-2993).
ENV=""

# Whether to drop per-service URL overrides from the config. Right for our
# deployments, where every service hangs off one base URL; a customer whose
# services sit on different hosts needs them kept.
RESET_CONFIG=false

# Whether a missing checksums.txt may be ignored.
SKIP_CHECKSUM=false

# PEM bundle of certificate authorities to trust, for a deployment behind an
# internal CA. The CLI reads it from ARTEMIS_SSL_CERT_FILE, which had no way in
# from the installer (ART-2993).
CA_CERT=""

# Whether a plain-HTTP deployment URL is acceptable. Every CLI call carries the
# API key as a bearer token, so HTTP sends it unencrypted - which is what our dev
# deployment did on every call (ART-2993).
ALLOW_INSECURE_HTTP=false

# A binary already on this machine, for an install with no route to the file
# server, and the checksum to prove it.
FROM_FILE=""
EXPECTED_SHA=""

# Accept --flag=value as well as --flag value: split the former into the
# latter so the parser below only has to handle one shape.
args=()
for arg in "$@"; do
    case "$arg" in
        --*=*) args+=("${arg%%=*}" "${arg#*=}") ;;
        *)     args+=("$arg") ;;
    esac
done
set -- "${args[@]}"

# Parse arguments
while [[ $# -gt 0 ]]; do
    case $1 in
        --version)
            VERSION="$2"
            shift 2
            ;;
        --dev)
            DEV=true
            shift
            ;;
        --nightly)
            NIGHTLY=true
            shift
            ;;
        --env)
            # Deployment to point the CLI at: dev, stg, prod, or a full
            # URL. Selects endpoints only - the build channel is chosen
            # with --version/--nightly/--dev.
            ENV="$2"
            shift 2
            ;;
        --install-dir)
            INSTALL_DIR="$2"
            shift 2
            ;;
        --base-url)
            # Same as --env with a full URL.
            ENV="$2"
            shift 2
            ;;
        --reset-config)
            RESET_CONFIG=true
            shift
            ;;
        --skip-checksum)
            SKIP_CHECKSUM=true
            shift
            ;;
        --ca-cert)
            CA_CERT="$2"
            shift 2
            ;;
        --allow-insecure-http)
            ALLOW_INSECURE_HTTP=true
            shift
            ;;
        --download-url)
            # A mirror of the release server. Nothing to do with --base-url:
            # one is where the binary comes from, the other where it points.
            DOWNLOAD_ROOT="${2%/}"
            shift 2
            ;;
        --from-file)
            FROM_FILE="$2"
            shift 2
            ;;
        --checksum)
            EXPECTED_SHA="$2"
            shift 2
            ;;
        --help|-h)
            echo "Artemis CLI Installer"
            echo ""
            echo "Usage: $0 [options]"
            echo ""
            echo "Options:"
            echo "  --version <X.Y.Z>       Install a specific release (default: newest stable)"
            echo "  --nightly               Install the newest release incl. prereleases"
            echo "  --dev                   Install the rolling development build"
            echo "  --env <env>             Deployment to point the CLI at: dev, testing, stg,"
            echo "                          prod, or a full URL. Without this the existing"
            echo "                          configuration is left alone."
            echo "  --base-url <url>        Same as --env with a full URL"
            echo "                          (e.g., https://artemis.internal)"
            echo "  --reset-config          Also drop per-service URL overrides"
            echo "                          (USER_MGMT_URL, FALCON_URL, ...) from the config"
            echo "  --skip-checksum         Install even if the binary cannot be verified"
            echo "  --ca-cert <pem>         PEM bundle of certificate authorities to trust for"
            echo "                          the deployment (written to ARTEMIS_SSL_CERT_FILE)"
            echo "  --allow-insecure-http   Accept a plain-HTTP deployment URL, which sends"
            echo "                          your API key unencrypted (needed for --env dev)"
            echo "  --download-url <url>    Mirror to download the build from, instead of"
            echo "                          ${DOWNLOAD_ROOT}"
            echo "  --from-file <path>      Install a binary already on this machine"
            echo "  --checksum <sha256>     Expected SHA-256 of --from-file"
            echo "  --install-dir <dir>     Installation directory (default: ~/.local/bin)"
            echo "  --help, -h              Show this help message"
            echo ""
            echo "Examples:"
            echo "  $0                                        # Newest release, configuration untouched"
            echo "  $0 --version 1.2.0                        # Specific release"
            echo "  $0 --dev --env dev                        # Development build, dev endpoints"
            echo "  $0 --base-url https://artemis.internal    # Custom deployment"
            echo "  $0 --base-url https://artemis.internal --ca-cert /etc/pki/ca.pem"
            echo "  $0 --download-url https://mirror.internal/artemis-cli"
            echo "  $0 --from-file ./artemis-cli-linux-amd64 --checksum <sha256>"
            exit 0
            ;;
        *)
            echo -e "${RED}Unknown option: $1${NC}"
            exit 1
            ;;
    esac
done

# Set default install directory if not specified
if [ -z "$INSTALL_DIR" ]; then
    INSTALL_DIR="$DEFAULT_INSTALL_DIR"
fi

# A local binary is not a channel, and not something to download.
if [ -n "$FROM_FILE" ]; then
    if [ "$DEV" = true ] || [ "$NIGHTLY" = true ] || [ -n "$VERSION" ]; then
        echo -e "${RED}--from-file installs the binary you give it; drop --dev/--nightly/--version${NC}"
        exit 1
    fi
    if [ ! -r "$FROM_FILE" ]; then
        echo -e "${RED}Cannot read ${FROM_FILE}${NC}"
        exit 1
    fi
    if [ -z "$EXPECTED_SHA" ] && [ "$SKIP_CHECKSUM" != true ]; then
        # A binary handed over on a USB stick is the case where verification
        # matters most, so it is required rather than merely offered.
        echo -e "${RED}--from-file needs --checksum <sha256> (or --skip-checksum)${NC}"
        echo "Get it from the release server's checksums.txt, or from whoever gave you the binary."
        exit 1
    fi
fi

# Resolve the download channel from the version selection
SELECTED=0
[ "$DEV" = true ] && SELECTED=$((SELECTED + 1))
[ "$NIGHTLY" = true ] && SELECTED=$((SELECTED + 1))
[ -n "$VERSION" ] && SELECTED=$((SELECTED + 1))
if [ "$SELECTED" -gt 1 ]; then
    echo -e "${RED}--dev, --nightly and --version are mutually exclusive${NC}"
    exit 1
elif [ "$DEV" = true ]; then
    CHANNEL="dev"
elif [ "$NIGHTLY" = true ]; then
    CHANNEL="nightly"
elif [ -n "$VERSION" ]; then
    CHANNEL="${VERSION#v}"
else
    CHANNEL="latest"
fi

# Detect OS and architecture
detect_platform() {
    local os arch

    case "$(uname -s)" in
        Linux*)  os="linux" ;;
        Darwin*) os="darwin" ;;
        MINGW*|MSYS*|CYGWIN*) os="windows" ;;
        *)
            echo -e "${RED}Unsupported operating system: $(uname -s)${NC}"
            exit 1
            ;;
    esac

    case "$(uname -m)" in
        x86_64|amd64) arch="amd64" ;;
        arm64|aarch64) arch="arm64" ;;
        *)
            echo -e "${RED}Unsupported architecture: $(uname -m)${NC}"
            exit 1
            ;;
    esac

    echo "${os}-${arch}"
}

# Print banner
print_banner() {
    echo -e "${BLUE}"
    echo "╔═══════════════════════════════════════════════════════════╗"
    echo "║                    Artemis CLI Installer                  ║"
    echo "╚═══════════════════════════════════════════════════════════╝"
    echo -e "${NC}"
}

# Check for required commands
check_requirements() {
    local missing=()

    if ! command -v curl &> /dev/null; then
        missing+=("curl")
    fi

    if [ ${#missing[@]} -ne 0 ]; then
        echo -e "${RED}Missing required commands: ${missing[*]}${NC}"
        echo "Please install them and try again."
        exit 1
    fi
}

# Download a file from the release server. The public paths need no
# credentials, and the pair this script used to carry was both unnecessary and
# printed in its own usage text (ART-2993).
#
# --ca-cert applies here too: a mirror inside the customer's network is signed by
# the same internal CA as their deployment, and without it the download failed
# while the connection test, which did pass the bundle, would have worked.
download_file() {
    local url="$1"
    local output="$2"
    local args=(-fL --progress-bar)
    if [ -n "$CA_CERT" ]; then
        args+=(--cacert "$CA_CERT")
    fi

    curl "${args[@]}" "${url}" -o "${output}"
}

# curl's own error line from a captured stderr ("curl: (60) SSL certificate
# problem: ..."), without the progress bar it shares the stream with.
curl_reason() {
    tr '\r' '\n' < "$1" | grep '^curl: ' | tail -1
}

# What to try after a download failed with curl exit status $1.
download_hint() {
    local status="$1"
    case "$status" in
        60|77|35|58|83)
            if [ -n "$CA_CERT" ]; then
                echo "The bundle at ${CA_CERT} does not cover the download server's certificate."
            else
                echo "If the download server uses an internal certificate authority, re-run with:"
                echo "  --ca-cert /path/to/ca.pem"
            fi
            ;;
    esac
    echo "Without a route to a release server, install a binary you already have with:"
    echo "  --from-file <path> --checksum <sha256>"
}

# Verify checksum
verify_checksum() {
    local file="$1"
    local expected="$2"

    if command -v sha256sum &> /dev/null; then
        actual=$(sha256sum "$file" | awk '{print $1}')
    elif command -v shasum &> /dev/null; then
        actual=$(shasum -a 256 "$file" | awk '{print $1}')
    else
        echo -e "${YELLOW}Warning: Cannot verify checksum (sha256sum/shasum not found)${NC}"
        return 0
    fi

    if [ "$actual" = "$expected" ]; then
        return 0
    else
        echo -e "${RED}Checksum verification failed!${NC}"
        echo "Expected: $expected"
        echo "Got:      $actual"
        return 1
    fi
}

# Main installation
main() {
    print_banner
    check_requirements

    local platform=$(detect_platform)
    local binary_suffix=""

    if [[ "$platform" == windows-* ]]; then
        binary_suffix=".exe"
    fi

    local binary_file="artemis-cli-${platform}${binary_suffix}"
    local download_url="${DOWNLOAD_ROOT}/${CHANNEL}/${binary_file}"
    local checksums_url="${DOWNLOAD_ROOT}/${CHANNEL}/checksums.txt"

    echo -e "${BLUE}Platform:${NC} ${platform}"
    if [ -n "$FROM_FILE" ]; then
        echo -e "${BLUE}Source:${NC} ${FROM_FILE}"
    else
        echo -e "${BLUE}Channel:${NC} ${CHANNEL}"
        echo -e "${BLUE}Source:${NC} ${download_url}"
    fi
    echo -e "${BLUE}Install directory:${NC} ${INSTALL_DIR}"
    echo ""

    # Create temp directory
    local tmp_dir=$(mktemp -d)
    trap "rm -rf $tmp_dir" EXIT

    if [ -n "$FROM_FILE" ]; then
        # An install with no route to the file server: the binary is already
        # here, and the checksum is the only thing vouching for it.
        cp "$FROM_FILE" "${tmp_dir}/${binary_file}"
        if [ -n "$EXPECTED_SHA" ]; then
            echo -e "${BLUE}Verifying checksum...${NC}"
            if ! verify_checksum "${tmp_dir}/${binary_file}" "$EXPECTED_SHA"; then
                exit 1
            fi
            echo -e "${GREEN}Checksum verified!${NC}"
        else
            echo -e "${YELLOW}Warning: installing ${FROM_FILE} unverified (--skip-checksum)${NC}"
        fi
        install_binary "${tmp_dir}/${binary_file}" "${binary_suffix}"
        return
    fi

    # Download checksums. A binary that cannot be verified is not installed:
    # skipping verification on a fetch failure made a truncated or substituted
    # download indistinguishable from a good one.
    #
    # curl's error is kept and shown: hidden, a certificate problem read as "check
    # the channel name and your network", which sent people the wrong way.
    echo -e "${BLUE}Downloading checksums...${NC}"
    local curl_err="${tmp_dir}/curl.err" status=0
    download_file "${checksums_url}" "${tmp_dir}/checksums.txt" 2>"$curl_err" || status=$?
    if [ "$status" -ne 0 ]; then
        local reason
        reason=$(curl_reason "$curl_err")
        if [ "$SKIP_CHECKSUM" = true ]; then
            echo -e "${YELLOW}Warning: could not download checksums${reason:+ (${reason})}; installing unverified (--skip-checksum)${NC}"
            rm -f "${tmp_dir}/checksums.txt"
        else
            echo -e "${RED}Could not download ${checksums_url}${NC}"
            [ -n "$reason" ] && echo "  ${reason}"
            echo "The binary cannot be verified. Check the channel name, your network,"
            echo "and --download-url if you install from a mirror."
            download_hint "$status"
            exit 1
        fi
    fi

    # Download binary
    echo -e "${BLUE}Downloading artemis-cli for ${platform}...${NC}"
    status=0
    download_file "${download_url}" "${tmp_dir}/${binary_file}" || status=$?
    if [ "$status" -ne 0 ]; then
        echo -e "${RED}Failed to download binary from ${download_url}${NC}"
        echo "Install from a mirror with --download-url."
        download_hint "$status"
        exit 1
    fi

    # Verify checksum if available
    if [ -f "${tmp_dir}/checksums.txt" ]; then
        echo -e "${BLUE}Verifying checksum...${NC}"
        expected_checksum=$(grep "${binary_file}" "${tmp_dir}/checksums.txt" | awk '{print $1}')
        if [ -z "$expected_checksum" ]; then
            if [ "$SKIP_CHECKSUM" = true ]; then
                echo -e "${YELLOW}Warning: ${binary_file} is absent from checksums.txt; installing unverified${NC}"
            else
                echo -e "${RED}${binary_file} is not listed in checksums.txt${NC}"
                echo "Re-run with --skip-checksum to install without verification."
                exit 1
            fi
        else
            if ! verify_checksum "${tmp_dir}/${binary_file}" "$expected_checksum"; then
                exit 1
            fi
            echo -e "${GREEN}Checksum verified!${NC}"
        fi
    fi

    install_binary "${tmp_dir}/${binary_file}" "${binary_suffix}"
}

# Put the verified binary in place and report what happened. Shared by the
# download and the --from-file paths, so both back the old build up, name what
# they replaced, and read the version from what was just installed.
install_binary() {
    local staged="$1"
    local binary_suffix="$2"
    local target="${INSTALL_DIR}/${BINARY_NAME}${binary_suffix}"

    # An upgrade that says nothing about what it replaced leaves no way to tell
    # which build is at fault, and no way back to one that worked.
    if [ -f "$target" ]; then
        local previous
        previous=$("$target" version 2>/dev/null | head -1 || echo "unknown version")
        echo -e "${BLUE}Replacing ${previous} (${target})${NC}"
        if cp -p "$target" "${target}.previous" 2>/dev/null; then
            echo -e "${BLUE}Previous binary kept at ${target}.previous${NC}"
        elif sudo cp -p "$target" "${target}.previous" 2>/dev/null; then
            echo -e "${BLUE}Previous binary kept at ${target}.previous${NC}"
        else
            echo -e "${YELLOW}Warning: could not keep a copy of the previous binary${NC}"
        fi
    fi

    echo -e "${BLUE}Installing to ${target}...${NC}"

    # Create install directory if it doesn't exist
    if [ ! -d "${INSTALL_DIR}" ]; then
        if ! mkdir -p "${INSTALL_DIR}" 2>/dev/null; then
            echo -e "${YELLOW}Creating ${INSTALL_DIR} requires sudo...${NC}"
            sudo mkdir -p "${INSTALL_DIR}"
        fi
    fi

    # Check if we need sudo
    if [ -w "${INSTALL_DIR}" ]; then
        mv "$staged" "$target"
        chmod +x "$target"
    else
        echo -e "${YELLOW}Installation to ${INSTALL_DIR} requires sudo...${NC}"
        echo -e "${YELLOW}You may be prompted for your password.${NC}"
        sudo mv "$staged" "$target"
        sudo chmod +x "$target"
    fi

    # Report the outcome. The version is read from the binary just installed:
    # `artemis` on PATH may be an older copy elsewhere, which reported the wrong
    # build as the outcome of the install.
    #
    # One ending for every case: whether the CLI happens to be on PATH decides
    # what advice follows, not whether the version, the configuration or the
    # connection test are reported at all (which is how a PATH-less machine got
    # a different install report altogether).
    echo ""
    local installed_version
    installed_version=$("$target" version 2>/dev/null | head -1 || echo "unknown")
    local on_path=""
    on_path=$(command -v "${BINARY_NAME}" 2>/dev/null || true)

    if [ -n "$on_path" ] && [ "$on_path" = "$target" ]; then
        echo -e "${GREEN}╔═══════════════════════════════════════════════════════════╗${NC}"
        echo -e "${GREEN}║           Artemis CLI installed successfully!             ║${NC}"
        echo -e "${GREEN}╚═══════════════════════════════════════════════════════════╝${NC}"
        echo ""
    fi
    echo -e "Version: ${installed_version}"
    echo -e "Installed at: ${target}"
    echo ""

    configure_environment
    if [ -n "$CONFIGURED_URL" ]; then
        test_connection "$CONFIGURED_URL"
    elif [ -n "$CA_CERT" ]; then
        echo -e "${YELLOW}No deployment given, so the connection was not tested.${NC}"
        echo -e "${YELLOW}After 'artemis login --url <url>', check it with: artemis status${NC}"
        echo ""
    fi

    if [ -z "$on_path" ]; then
        echo -e "${YELLOW}Warning: '${BINARY_NAME}' is not on your PATH.${NC}"
        echo "Add ${INSTALL_DIR} to it by running:"
        echo "  echo 'export PATH=\"\$PATH:${INSTALL_DIR}\"' >> ~/.bashrc"
        echo "  source ~/.bashrc"
        echo ""
        echo "Or run the binary directly:"
        echo "  ${target} --help"
        echo ""
    elif [ "$on_path" != "$target" ]; then
        echo -e "${YELLOW}Note: '${BINARY_NAME}' on your PATH is ${on_path}, not the binary just installed.${NC}"
        echo ""
    fi

    echo -e "${BLUE}Quick start:${NC}"
    echo "  artemis login          Connect and store your API key"
    echo "  artemis --help         Show available commands"
    echo "  artemis status         Check configuration status"
}

# The config file every artemis command reads. Created empty if absent.
config_path() {
    local config_dir="$HOME/.config/artemis"
    mkdir -p "$config_dir"
    touch "${config_dir}/.env"
    echo "${config_dir}/.env"
}

# Copy the config aside before the first change of this run. It holds the API key
# and, on a customer deployment, per-service URLs that nothing else records.
CONFIG_BACKUP=""

# The deployment configure_environment settled on, for the connection test.
CONFIGURED_URL=""
backup_config_once() {
    local config_file="$1"
    if [ -n "$CONFIG_BACKUP" ] || [ ! -s "$config_file" ]; then
        return 0
    fi
    CONFIG_BACKUP="${config_file}.backup.$(date +%Y%m%d-%H%M%S)"
    cp -p "$config_file" "$CONFIG_BACKUP"
    chmod 600 "$CONFIG_BACKUP"
}

# Replace one KEY=value line, leaving every other line as it is.
set_config_var() {
    local config_file="$1" key="$2" value="$3"
    local tmp_file
    tmp_file=$(mktemp)
    grep -vE "^${key}=" "$config_file" > "$tmp_file" || true
    printf '%s=%s\n' "$key" "$value" >> "$tmp_file"
    mv "$tmp_file" "$config_file"
    chmod 600 "$config_file"
}

# Install the CA bundle a deployment behind an internal certificate authority
# needs. The CLI has read ARTEMIS_SSL_CERT_FILE all along; without a way to set
# it from here, a customer installed and then watched every command fail on TLS
# until they found the variable (ART-2993).
write_ca_cert() {
    if [ -z "$CA_CERT" ]; then
        return 0
    fi
    if [ ! -r "$CA_CERT" ]; then
        echo -e "${RED}Cannot read CA bundle ${CA_CERT}${NC}"
        return 1
    fi
    # A DER file or the wrong file entirely fails later inside the CLI, with an
    # error about the connection rather than about the bundle.
    if ! grep -q -- "-----BEGIN CERTIFICATE-----" "$CA_CERT"; then
        echo -e "${RED}${CA_CERT} does not contain a PEM certificate${NC}"
        echo "Expected a file with -----BEGIN CERTIFICATE-----. Convert DER with:"
        echo "  openssl x509 -inform der -in <file> -out ca.pem"
        return 1
    fi

    local config_dir="$HOME/.config/artemis"
    local installed="${config_dir}/ca.pem"
    local config_file
    config_file=$(config_path)
    backup_config_once "$config_file"

    # Copied rather than referenced: a bundle fetched to /tmp, or in a checkout
    # that moves, would leave every later command failing on a missing file.
    if [ "$(cd "$(dirname "$CA_CERT")" && pwd)/$(basename "$CA_CERT")" != "$installed" ]; then
        cp "$CA_CERT" "$installed"
        chmod 644 "$installed"
    fi
    set_config_var "$config_file" "ARTEMIS_SSL_CERT_FILE" "$installed"
    CA_CERT="$installed"

    echo -e "${GREEN}CA bundle installed (${installed}).${NC}"
    echo "  ARTEMIS_SSL_CERT_FILE=${installed}"
    echo ""
}

# Prove the deployment answers before saying the install is done, and name the
# cause when it does not: a TLS failure is a different problem from a wrong URL,
# and the message people reach for otherwise is ARTEMIS_SSL_VERIFY=false.
test_connection() {
    local url="$1"
    local probe="${url%/}/turintech-users-api/monitoring/health"
    local args=(-sS -o /dev/null -w '%{http_code}' --max-time 15)
    if [ -n "$CA_CERT" ]; then
        args+=(--cacert "$CA_CERT")
    fi

    echo -e "${BLUE}Testing the connection to ${url}...${NC}"
    local code status
    code=$(curl "${args[@]}" "$probe" 2>/dev/null) && status=0 || status=$?

    if [ "$status" -eq 0 ]; then
        # 401 is a reachable deployment with no key yet, which is the normal
        # state right after an install.
        echo -e "${GREEN}Reachable (HTTP ${code}).${NC}"
        echo ""
        return 0
    fi

    case "$status" in
        60|77|35|58|83)
            echo -e "${RED}TLS failed: the certificate ${url} presents is not trusted.${NC}"
            if [ -n "$CA_CERT" ]; then
                echo "The bundle at ${CA_CERT} does not cover it. Ask whoever issued the"
                echo "certificate for the full chain, including any intermediate CA."
            else
                echo "If this deployment uses an internal certificate authority, re-run with:"
                echo "  --ca-cert /path/to/ca.pem"
            fi
            echo -e "${YELLOW}Do not set ARTEMIS_SSL_VERIFY=false: it sends your API key to whatever answers.${NC}"
            ;;
        6)
            echo -e "${RED}Could not resolve the host in ${url}.${NC}"
            ;;
        7|28)
            echo -e "${RED}Could not reach ${url} (no answer).${NC}"
            echo "Check the URL, your VPN, and any proxy you need."
            ;;
        *)
            echo -e "${RED}Could not reach ${url} (curl exit ${status}).${NC}"
            ;;
    esac
    # The binary is installed and the configuration written; only the check
    # failed, and the user needs both facts.
    echo -e "${YELLOW}The CLI is installed and configured. Fix the above, then run: artemis status${NC}"
    echo ""
    return 0
}

# Scheme and host of a URL, lower-cased, with quotes and any trailing slash gone -
# the form config.SameDeployment compares. A stored value is whatever someone's
# editor left behind, so `http://host/` and `"http://host"` are the same
# deployment as `http://host`; comparing the text instead cleared a valid key
# (ART-2993 review).
deployment_of() {
    local url="$1"
    url="${url%\"}"; url="${url#\"}"
    url="${url%\'}"; url="${url#\'}"
    url=$(printf '%s' "$url" | tr -d '[:space:]')
    local scheme="${url%%://*}"
    local rest="${url#*://}"
    rest="${rest%%/*}"
    rest="${rest%%\?*}"
    rest="${rest%%#*}"
    rest="${rest##*@}"
    printf '%s' "$(printf '%s://%s' "$scheme" "$rest" | tr '[:upper:]' '[:lower:]')"
}

# Whether two URLs name the same deployment: scheme and host, ignoring the service
# path, as the CLI's config.SameDeployment does.
same_deployment() {
    [ -n "$1" ] && [ -n "$2" ] && [ "$(deployment_of "$1")" = "$(deployment_of "$2")" ]
}

# Whether a URL's host is this machine, by the same rule as the CLI's
# config.IsInsecureURL: matching the text let http://127.0.0.1.nip.io through as
# localhost, and the CLI then refused every command with that URL (ART-2993).
is_loopback_url() {
    local rest="${1#*://}"
    rest="${rest%%/*}"
    rest="${rest%%\?*}"
    rest="${rest%%#*}"
    rest="${rest##*@}"
    local host
    case "$rest" in
        \[*) host="${rest#\[}"; host="${host%%]*}" ;;
        *)   host="${rest%%:*}" ;;
    esac
    host=$(printf '%s' "$host" | tr '[:upper:]' '[:lower:]')
    case "$host" in
        localhost|127.0.0.1|::1|0.0.0.0|*.localhost) return 0 ;;
    esac
    return 1
}

# The URL of our production deployment, which only a stable build should use.
PROD_URL="https://artemis.turintech.ai"

# Point the CLI at the selected deployment, when one was chosen.
#
# Without --env or --base-url this leaves the configuration untouched: writing
# our production URL into every install pointed `--dev` builds, and every
# customer, at the wrong deployment without saying so (ART-2993).
configure_environment() {
    # The CA bundle is asked for explicitly, so it is written whether or not a
    # deployment was named.
    if ! write_ca_cert; then
        return 1
    fi

    if [ -z "$ENV" ]; then
        echo -e "${BLUE}Configuration left unchanged.${NC}"
        echo -e "${YELLOW}Point the CLI at your deployment with:${NC}"
        echo "  artemis login --url <url>      # or: --url dev|testing|stg|prod"
        echo ""
        return 0
    fi

    # Resolve named environments to their base URL; anything else is
    # taken as a full URL.
    local env_url
    case "$ENV" in
        dev)              env_url="http://dev.artemis.turintech.ai" ;;
        # The deployment QA runs the nightly build against. Its absence printed
        # "Unknown environment" for a name people were already using.
        testing|test)     env_url="https://testing.artemis.turintech.ai" ;;
        stg|staging)      env_url="https://staging.artemis.turintech.ai" ;;
        prod|production)  env_url="$PROD_URL" ;;
        http://*|https://*) env_url="${ENV%/}" ;;
        *)
            echo -e "${YELLOW}Unknown environment '${ENV}' - expected dev, testing, stg, prod, or a full URL.${NC}"
            echo -e "${YELLOW}Skipping endpoint configuration; run: artemis login --url <url>${NC}"
            echo ""
            return 0
            ;;
    esac

    # Every call sends the API key as a bearer token, so a plain-HTTP deployment
    # sends it in the clear. No exception for our dev deployment: it is the one
    # this was found on.
    case "$env_url" in
        http://*)
            if is_loopback_url "$env_url"; then
                :
            elif [ "$ALLOW_INSECURE_HTTP" != true ]; then
                echo -e "${RED}${env_url} sends your API key unencrypted.${NC}"
                echo "Use an https URL, or pass --allow-insecure-http if that is what you want."
                echo -e "${YELLOW}The CLI is installed; nothing was configured.${NC}"
                echo ""
                return 1
            else
                echo -e "${YELLOW}Warning: ${env_url} is plain HTTP; your API key will be sent unencrypted.${NC}"
            fi
            ;;
    esac

    # A dev or nightly build against production is usually a missing --env: the
    # channel and the deployment are chosen separately (ART-2993).
    if [ "$CHANNEL" = "dev" ] || [ "$CHANNEL" = "nightly" ]; then
        if [ "${env_url%/}" = "$PROD_URL" ]; then
            echo -e "${YELLOW}Warning: a ${CHANNEL} build is not a stable release, and this points it at production (${PROD_URL}).${NC}"
            echo -e "${YELLOW}For a pre-release deployment use --env dev or --env testing; for production, drop --${CHANNEL}.${NC}"
        fi
    fi

    # Write the config file directly rather than through the binary: older
    # releases seed missing configs with per-service dev URLs, which would
    # shadow the base URL we set here.
    local config_file
    config_file=$(config_path)

    echo -e "${BLUE}Pointing the CLI at ${env_url}...${NC}"
    backup_config_once "$config_file"

    local previous_url
    previous_url=$(grep -m1 '^ARTEMIS_BASE_URL=' "$config_file" | cut -d= -f2- || true)

    # Per-service URL overrides shadow ARTEMIS_BASE_URL. Dropping them is right
    # for our deployments and wrong for a customer whose services sit on
    # different hosts, so it only happens when asked for.
    local overrides_pattern='^(USER_MGMT_URL|AGENT_MGMT_URL|FALCON_URL|QUEST_URL|LLM_API_BASE_URL|CODE_WARDEN_URL)='
    local overrides=""
    overrides=$(grep -oE "$overrides_pattern" "$config_file" | tr -d '=' | sort -u | tr '\n' ' ' || true)

    local strip_pattern='^ARTEMIS_BASE_URL='
    local key_cleared=false
    if [ "$RESET_CONFIG" = true ]; then
        strip_pattern="^ARTEMIS_BASE_URL=|${overrides_pattern}"
    fi

    # A key belongs to the deployment it was issued by, so a changed URL leaves
    # it invalid: `artemis login` clears it on a URL change and this did not,
    # which left a stale key reporting itself as fine (ART-2993).
    #
    # It is kept only when the old config named this same deployment. One with no
    # ARTEMIS_BASE_URL - written before it existed, with per-service URLs - says
    # nothing that ties its key to this URL, and keeping it sent a staging key to
    # Testing.
    if ! same_deployment "$previous_url" "$env_url" && grep -q '^ARTEMIS_API_KEY=' "$config_file"; then
        strip_pattern="${strip_pattern}|^ARTEMIS_API_KEY="
        key_cleared=true
    fi

    local tmp_file
    tmp_file=$(mktemp)
    grep -vE "${strip_pattern}|^ARTEMIS_ALLOW_INSECURE_HTTP=" "$config_file" > "$tmp_file" || true
    printf 'ARTEMIS_BASE_URL=%s\n' "$env_url" >> "$tmp_file"
    # Recorded with the URL it was given for, so every later command does not
    # need the flag, and so the file says plainly that this deployment is used
    # over plain HTTP.
    case "$env_url" in
        http://*)
            is_loopback_url "$env_url" || printf 'ARTEMIS_ALLOW_INSECURE_HTTP=true\n' >> "$tmp_file"
            ;;
    esac
    mv "$tmp_file" "$config_file"
    chmod 600 "$config_file"

    # Say what changed. The old script rewrote the file silently, so a customer
    # upgrading had no way to see what it had taken out.
    echo -e "${GREEN}Endpoints configured (${env_url}).${NC}"
    if [ -n "$previous_url" ] && [ "$previous_url" != "$env_url" ]; then
        echo "  ARTEMIS_BASE_URL: ${previous_url} -> ${env_url}"
    else
        echo "  ARTEMIS_BASE_URL: ${env_url}"
    fi
    if [ "$key_cleared" = true ]; then
        if [ -n "$previous_url" ]; then
            echo "  ARTEMIS_API_KEY: cleared (it was issued by ${previous_url})"
        else
            echo "  ARTEMIS_API_KEY: cleared (the old configuration named no ARTEMIS_BASE_URL,"
            echo "  so the key may belong to another deployment)"
        fi
    fi
    if [ -n "$overrides" ]; then
        if [ "$RESET_CONFIG" = true ]; then
            echo "  removed per-service URLs: ${overrides}"
        else
            echo -e "${YELLOW}  kept per-service URLs: ${overrides}${NC}"
            echo -e "${YELLOW}  These override ARTEMIS_BASE_URL. Drop them with --reset-config if they are stale.${NC}"
        fi
    fi
    if [ -n "$CONFIG_BACKUP" ]; then
        echo "  previous configuration saved to ${CONFIG_BACKUP}"
    fi

    CONFIGURED_URL="$env_url"

    echo -e "${YELLOW}Note: Finish setup with: artemis login --url ${env_url}${NC}"
    echo ""
}

# Sourced by scripts/artemis-cli-installer.test.sh, which exercises the
# configuration handling without downloading anything.
if [ "${ARTEMIS_INSTALLER_LIB:-}" != "1" ]; then
    main "$@"
fi
