#!/usr/bin/env bash
set -euo pipefail

# Configurable via environment
VERSION="${COSINE_VERSION:-latest}"
INSTALL_DIR="${COSINE_INSTALL_DIR:-}"
API_BASE_URL="${COSINE_API_BASE_URL:-https://api.cosine.sh}"
REPO_OWNER="CosineAI"
CLI_REPO_NAME="cli2"
CLI_BINARY_NAME="cos"

print_status() { printf "%s\n" "$1" >&2; }
print_success() { printf "[SUCCESS] %s\n" "$1" >&2; }
print_warning() {
  if [ -z "${NO_COLOR:-}" ]; then
    orange=$(printf '\033[38;5;208m')
    reset=$(printf '\033[0m')
    printf "%s[WARNING] %s%s\n" "$orange" "$1" "$reset" >&2
  else
    printf "[WARNING] %s\n" "$1" >&2
  fi
}

print_error() {
  if [ -z "${NO_COLOR:-}" ]; then
    red=$(printf '\033[0;31m')
    reset=$(printf '\033[0m')
    printf "%s[ERROR] %s%s\n" "$red" "$1" "$reset" >&2
  else
    printf "[ERROR] %s\n" "$1" >&2
  fi
}

err() { print_error "$*"; }

show_logo() {
  printf "\n" >&2

  if [ -z "${NO_COLOR:-}" ]; then
    c1=$(printf '\033[38;5;213m')
    c2=$(printf '\033[38;5;177m')
    c3=$(printf '\033[38;5;141m')
    c4=$(printf '\033[38;5;135m')
    c5=$(printf '\033[38;5;129m')
    reset=$(printf '\033[0m')

    printf "%s   ✬✬✬✫✫✩✧✦☆✦%s\n" "$c1" "$reset" >&2
    printf "%s ✬✬✬✬✬✬ ✪✧☆☆✦%s\n" "$c1" "$reset" >&2
    printf "%s✬✬✬✬✬✬  ✬✧✦✦✦%s%s     ✬✬✬✬✬✬✬   ✬✬✬✬✬✬✬   ✬✬✬✬✬✬✬  ✬✬  ✬✬✬    ✬✬  ✬✬✬✬✬✬✬✬%s\n" "$c1" "$reset" "$c2" "$reset" >&2
    printf "%s✩✪✬✬      ✬✪✪%s%s    ✬✬     ✬✬ ✬✬     ✬✬ ✬✬        ✬✬  ✬✬✬✬✬  ✬✬  ✬✬%s\n" "$c2" "$reset" "$c3" "$reset" >&2
    printf "%s                 ✬✬%s%s        ✬✬     ✬✬  ✬✬✬✬✬✬✬  ✬✬  ✬✬ ✬✬✬ ✬✬  ✬✬✬✬✬✬✬✬%s\n" "$c2" "$reset" "$c3" "$reset" >&2
    printf "%s✩✪✩✩      ✪✪✪%s%s    ✬✬     ✬✬ ✬✬     ✬✬ ✬✬     ✬✬ ✬✬  ✬✬   ✬✬✬✬  ✬✬%s\n" "$c4" "$reset" "$c4" "$reset" >&2
    printf "%s✪✪✪✪✩✩  ✫✫✫✫✫%s%s     ✬✬✬✬✬✬✬   ✬✬✬✬✬✬✬   ✬✬✬✬✬✬✬  ✬✬  ✬✬    ✬✬✬  ✬✬✬✬✬✬✬✬%s\n" "$c4" "$reset" "$c5" "$reset" >&2
    printf "%s ✬✬✬✬✬✬ ✬✪✪✫✫%s\n" "$c5" "$reset" >&2
    printf "%s   ✬✬✬✫✪✩✩✪✪✫%s\n" "$c5" "$reset" >&2
  else
    printf "   ✬✬✬✫✫✩✧✦☆✦\n" >&2
    printf " ✬✬✬✬✬✬ ✪✧☆☆✦\n" >&2
    printf "✬✬✬✬✬✬  ✬✧✦✦✦     ✬✬✬✬✬✬✬   ✬✬✬✬✬✬✬   ✬✬✬✬✬✬✬  ✬✬  ✬✬✬    ✬✬  ✬✬✬✬✬✬✬✬\n" >&2
    printf "✩✪✬✬      ✬✪✪    ✬✬     ✬✬ ✬✬     ✬✬ ✬✬        ✬✬  ✬✬✬✬✬  ✬✬  ✬✬\n" >&2
    printf "                 ✬✬        ✬✬     ✬✬  ✬✬✬✬✬✬✬  ✬✬  ✬✬ ✬✬✬ ✬✬  ✬✬✬✬✬✬✬✬\n" >&2
    printf "✩✪✩✩      ✪✪✪    ✬✬     ✬✬ ✬✬     ✬✬ ✬✬     ✬✬ ✬✬  ✬✬   ✬✬✬✬  ✬✬\n" >&2
    printf "✪✪✪✪✩✩  ✫✫✫✫✫     ✬✬✬✬✬✬✬   ✬✬✬✬✬✬✬   ✬✬✬✬✬✬✬  ✬✬  ✬✬    ✬✬✬  ✬✬✬✬✬✬✬✬\n" >&2
    printf " ✬✬✬✬✬✬ ✬✪✪✫✫\n" >&2
    printf "   ✬✬✬✫✪✩✩✪✪✫\n" >&2
  fi

  printf "\n" >&2
}

need_cmd() { command -v "$1" >/dev/null 2>&1 || {
  err "Required command not found: $1"
  return 1
}; }

python_cmd() {
  if command -v python3 >/dev/null 2>&1; then
    printf "%s\n" "python3"
  elif command -v python >/dev/null 2>&1; then
    printf "%s\n" "python"
  else
    printf "%s\n" ""
  fi
}

fetch_cli_latest_json() {
  local version="$1" os="$2" arch="$3"

  curl -fsSL --get \
    --data-urlencode "version=$version" \
    --data-urlencode "os=$os" \
    --data-urlencode "arch=$arch" \
    "${API_BASE_URL%/}/cli/latest"
}

json_get_string_field() {
  local json="$1" key="$2"
  printf "%s" "$json" | awk -F'"' -v k="$key" '
    {
      for (i = 1; i <= NF; i++) {
        if ($i == k) {
          print $(i + 2)
          exit
        }
      }
    }
  '
}

resolve_cli_latest_and_url() {
  local version="$1" os="$2" arch="$3" json latest url

  json="$(fetch_cli_latest_json "$version" "$os" "$arch")"
  latest="$(json_get_string_field "$json" "latest")"
  url="$(json_get_string_field "$json" "download_url")"

  if [ -z "$latest" ]; then
    err "Unable to resolve latest cli version from Cosine API (${API_BASE_URL%/}/cli/latest)."
    exit 1
  fi

  printf "%s|%s\n" "$latest" "$url"
}

normalize_version() {
  local v="${1-}"
  if [ -z "${v}" ]; then
    printf "%s\n" "$VERSION"
    return
  fi
  case "$v" in
  latest | nightly | nightly-*)
    printf "%s\n" "$v"
    return
    ;;
  esac
  if [[ "$v" == *"-v"* ]]; then
    v="${v#*-v}"
    v="v${v}"
  fi
  printf "%s\n" "$v"
}

detect_os_arch() {
  local os arch
  os="$(uname -s)"
  arch="$(uname -m)"

  case "$os" in
  Linux) os="linux" ;;
  Darwin) os="darwin" ;;
  *)
    err "Unsupported OS: $os"
    exit 1
    ;;
  esac

  case "$arch" in
  x86_64 | amd64) arch="amd64" ;;
  arm64 | aarch64) arch="arm64" ;;
  *)
    err "Unsupported architecture: $arch"
    exit 1
    ;;
  esac

  if [ "$os" = "darwin" ] && [ "$arch" != "arm64" ]; then
    err "macOS amd64 is not supported by prebuilt binaries. Use Rosetta or Homebrew."
    exit 1
  fi

  print_status "Detected platform: ${os}-${arch}"
  printf "%s %s\n" "$os" "$arch"
}

linux_glibc_version() {
  # Returns "major.minor" for glibc if detectable, or empty string otherwise
  if command -v getconf >/dev/null 2>&1; then
    v="$(getconf GNU_LIBC_VERSION 2>/dev/null || true)"
    # Expected format: "glibc 2.35"
    case "$v" in
    *glibc*" "*) v="${v##* }" ;; # take last space-separated token
    esac
    printf "%s\n" "$v"
    return
  fi

  if command -v ldd >/dev/null 2>&1; then
    # ldd --version prints glibc version on first line: "ldd (Ubuntu GLIBC 2.35-0ubuntu3.6) 2.35"
    v="$(ldd --version 2>/dev/null | head -n1)"
    # Try to extract last "X.Y" pattern
    v="$(printf "%s" "$v" | sed -n 's/.* \([0-9]\+\.[0-9]\+\).*/\1/p')"
    printf "%s\n" "$v"
    return
  fi

  printf "\n"
}

extract_zip() {
  local zip="$1" dest="$2" py
  if command -v unzip >/dev/null 2>&1; then
    unzip -q "$zip" -d "$dest"
  else
    py="$(python_cmd)"
    if [ -z "$py" ]; then
      err "unzip is not available and no Python interpreter was found to extract ${zip}."
      err "Install unzip or python3 and re-run."
      exit 1
    fi
    "$py" - "$zip" "$dest" <<'PY'
import sys, zipfile, os
zip_path, dest = sys.argv[1], sys.argv[2]
os.makedirs(dest, exist_ok=True)
with zipfile.ZipFile(zip_path) as z:
    z.extractall(dest)
PY
  fi
}

choose_install_dir() {
  # Respect explicit override
  if [ -n "${INSTALL_DIR:-}" ]; then
    print_status "Using install directory from COSINE_INSTALL_DIR: ${INSTALL_DIR}"
    printf "%s\n" "$INSTALL_DIR"
    return
  fi

  # Default to user-space install to avoid requiring sudo
  if [ -n "${HOME:-}" ]; then
    if [ -d "$HOME/.local/bin" ] || mkdir -p "$HOME/.local/bin" 2>/dev/null; then
      printf "%s\n" "$HOME/.local/bin"
      return
    fi
    if [ -d "$HOME/bin" ] || mkdir -p "$HOME/bin" 2>/dev/null; then
      printf "%s\n" "$HOME/bin"
      return
    fi
  fi

  for d in /usr/local/bin /usr/bin; do
    if [ -d "$d" ]; then
      printf "%s\n" "$d"
      return
    fi
  done

  # Last resort
  printf "%s\n" "/usr/local/bin"
}

install_file() {
  local src="$1" dst_dir="$2" name="$3" dst
  dst="$2/$name"
  if [ -w "$dst_dir" ] 2>/dev/null; then
    chmod +x "$src"
    mv -f "$src" "$dst"
  else
    if command -v sudo >/dev/null 2>&1; then
      sudo sh -c "install -m 0755 \"$src\" \"$dst\" 2>/dev/null || { mkdir -p \"$dst_dir\" && install -m 0755 \"$src\" \"$dst\"; }"
    else
      # Fallback to user-space install if system dir is not writable
      local user_dir
      user_dir="$(choose_install_dir)"
      if [ ! -w "$user_dir" ] && [ "$user_dir" = "$dst_dir" ]; then
        user_dir="$HOME/.local/bin"
        mkdir -p "$user_dir"
      fi
      chmod +x "$src"
      mv -f "$src" "$user_dir/$name"
      dst="$user_dir/$name"
      dst_dir="$user_dir"
    fi
  fi
  printf "%s\n" "$dst"
}

install_cli() {
  local version="$1" os="$2" arch="$3"
  local resolved_version="$version" url="" asset="" base_url=""

  case "$version" in
  latest | beta)
    case "$os" in
    darwin) asset="cos-darwin-arm64.zip" ;;
    linux)
      if [ "$arch" = "amd64" ]; then
        glibc_ver="$(linux_glibc_version)"
        if [ -n "$glibc_ver" ]; then
          glibc_major="${glibc_ver%%.*}"
          glibc_minor="${glibc_ver#*.}"
          if [ "$glibc_major" -eq 2 ] && [ "$glibc_minor" -lt 39 ]; then
            asset="cos-linux-amd64-glibc2.35.zip"
          else
            asset="cos-linux-amd64.zip"
          fi
        else
          asset="cos-linux-amd64.zip"
        fi
      else
        asset="cos-linux-arm64.zip"
      fi
      ;;
    esac

    url="https://software.cosine.sh/cli/release/latest/${asset}"
    resolved_version="latest"
    ;;
  nightly)
    IFS="|" read -r resolved_version url < <(resolve_cli_latest_and_url "$version" "$os" "$arch")
    if [ -z "$url" ]; then
      err "Cosine API did not return a download_url for cli ${version} (os=$os arch=$arch)."
      exit 1
    fi
    # The API conservatively returns the glibc2.35 build for Linux amd64.
    # Upgrade to the standard build if the local glibc is >= 2.39.
    if [ "$os" = "linux" ] && [ "$arch" = "amd64" ]; then
      glibc_ver="$(linux_glibc_version)"
      if [ -n "$glibc_ver" ]; then
        glibc_major="${glibc_ver%%.*}"
        glibc_minor="${glibc_ver#*.}"
        if [ "$glibc_major" -eq 2 ] && [ "$glibc_minor" -ge 39 ]; then
          url="${url/cos-linux-amd64-glibc2.35.zip/cos-linux-amd64.zip}"
          url="${url/cos2-linux-amd64-glibc2.35.zip/cos-linux-amd64.zip}"
        fi
      fi
    fi
    if [ "$os" = "linux" ] && [ "$arch" = "arm64" ]; then
      glibc_ver="$(linux_glibc_version)"
      if [ -n "$glibc_ver" ]; then
        glibc_major="${glibc_ver%%.*}"
        glibc_minor="${glibc_ver#*.}"
        if [ "$glibc_major" -eq 2 ] && [ "$glibc_minor" -lt 39 ]; then
          err "The cos2 Linux arm64 binary requires glibc 2.39 or later."
          err "Your system has glibc ${glibc_ver}. The arm64 build does not have a glibc2.35 compatibility variant."
          err "Please upgrade your system's glibc (e.g. upgrade to Ubuntu 24.04 or later)."
          exit 1
        fi
      fi
    fi
    asset="${url##*/}"
    ;;
  *)
    case "$os" in
    darwin) asset="cos-darwin-arm64.zip" ;;
    linux)
      if [ "$arch" = "amd64" ]; then
        glibc_ver="$(linux_glibc_version)"
        if [ -n "$glibc_ver" ]; then
          glibc_major="${glibc_ver%%.*}"
          glibc_minor="${glibc_ver#*.}"
          if [ "$glibc_major" -eq 2 ] && [ "$glibc_minor" -lt 39 ]; then
            asset="cos-linux-amd64-glibc2.35.zip"
          else
            asset="cos-linux-amd64.zip"
          fi
        else
          asset="cos-linux-amd64.zip"
        fi
      else
        glibc_ver="$(linux_glibc_version)"
        if [ -n "$glibc_ver" ]; then
          glibc_major="${glibc_ver%%.*}"
          glibc_minor="${glibc_ver#*.}"
          if [ "$glibc_major" -eq 2 ] && [ "$glibc_minor" -lt 39 ]; then
            err "The cos2 Linux arm64 binary requires glibc 2.39 or later."
            err "Your system has glibc ${glibc_ver}. The arm64 build does not have a glibc2.35 compatibility variant."
            err "Please upgrade your system's glibc (e.g. upgrade to Ubuntu 24.04 or later)."
            exit 1
          fi
        fi
        asset="cos2-linux-arm64.zip"
      fi
      ;;
    esac

    base_url="https://github.com/${REPO_OWNER}/${CLI_REPO_NAME}/releases/download/${resolved_version}"
    url="${base_url}/${asset}"
    ;;
  esac

  tmpdir="$(mktemp -d)"
  trap 'rm -rf "$tmpdir"' EXIT

  if [ "$version" = "$resolved_version" ]; then
    print_status "Downloading ${asset} from ${resolved_version}..."
  else
    print_status "Downloading ${asset} from ${version} (${resolved_version})..."
  fi
  print_status "Download URL: ${url}"

  curl -fsSL -o "${tmpdir}/${asset}" "$url"

  extract_dir="${tmpdir}/out"
  print_status "Extracting archive..."
  extract_zip "${tmpdir}/${asset}" "$extract_dir"

  archive_binary_name="$CLI_BINARY_NAME"
  if [ ! -f "${extract_dir}/${archive_binary_name}" ] && [ -f "${extract_dir}/cos" ]; then
    archive_binary_name="cos"
  fi

  if [ ! -f "${extract_dir}/${archive_binary_name}" ]; then
    err "Binary '${CLI_BINARY_NAME}' not found in archive"
    exit 1
  fi

  dest_dir="$(choose_install_dir)"
  installed_path="$(install_file "${extract_dir}/${archive_binary_name}" "$dest_dir" "${CLI_BINARY_NAME}")"
  installed_dir="$(dirname "$installed_path")"

  print_success "Installed to: ${installed_path}"

  active_path="$(command -v "${CLI_BINARY_NAME}" 2>/dev/null || true)"

  case ":${PATH:-}:" in
  *":${installed_dir}:"*)
    if [ -n "$active_path" ] && [ "$active_path" != "$installed_path" ]; then
      err "Note: another '${CLI_BINARY_NAME}' was found on PATH: ${active_path}"
      err "To use the installed binary, ensure ${installed_dir} appears before it in your PATH."
    fi
    "$installed_path" version || "$installed_path" --version || true
    ;;
  *)
    print_warning "${installed_dir} is not currently in PATH"
    echo "Add ${installed_dir} to your PATH, for example:" >&2
    shell_rc=""
    if [ -n "${ZSH_VERSION:-}" ]; then shell_rc="$HOME/.zshrc"; elif [ -n "${BASH_VERSION:-}" ]; then shell_rc="$HOME/.bashrc"; fi
    if [ -n "$shell_rc" ]; then
      echo "  echo 'export PATH=\"${installed_dir}:\$PATH\"' >> \"$shell_rc\"" >&2
      echo "  source \"$shell_rc\"" >&2
    else
      echo "  export PATH=\"${installed_dir}:\$PATH\"" >&2
    fi
    ;;
  esac
}

main() {
  show_logo
  print_status "Starting Cosine CLI installation..."

  need_cmd uname
  need_cmd curl
  need_cmd awk

  if [ "${1-}" = "-h" ] || [ "${1-}" = "--help" ]; then
    echo "Usage:" >&2
    echo "  curl -fsSL https://cosine.sh/install | bash -s -- [VERSION]" >&2
    echo "" >&2
    echo "VERSION can be: latest | nightly | nightly-<n> | vX.Y.Z | vX.Y.Z-betaN" >&2
    exit 0
  fi

  version_arg="${1-}"
  if [ "$version_arg" = "cos2" ] || [ "$version_arg" = "cli2" ]; then
    shift
    version_arg="${1-}"
  fi

  VERSION="$(normalize_version "$version_arg")"

  if [ "$VERSION" = "beta" ]; then
    err "The 'beta' flag is no longer supported. Use 'latest' instead."
    exit 1
  fi

  read -r os arch < <(detect_os_arch)
  install_cli "$VERSION" "$os" "$arch"

  print_success "Installation complete"
  echo >&2
  print_status "Next steps:"
  echo "  1. Run 'cos login' to authenticate" >&2
  echo "  2. Start the Cosine UI with 'cos' (or 'cos start')" >&2
  echo >&2
  echo "Cosine CLI quick tips:" >&2
  echo "- 'cos' loads the folder you're currently in." >&2
  echo "- To use a different project, cd into it first, or run: cos --cwd=/path/to/project" >&2
  echo "- Run one-shot tasks without the UI: cos start --prompt \"your prompt\"" >&2
  echo >&2

  prompt_1="Look through my codebase and identify 1 major bottleneck to optimize."
  prompt_2="Find the slowest build step in this repo and suggest concrete speedups."
  prompt_3="Audit this project for expensive DB queries and propose query/index fixes."
  prompt_4="Profile likely hot paths and recommend the highest-ROI optimization first."
  prompt_5="Find unnecessary network calls and suggest batching or caching improvements."
  prompt_6="Identify 3 memory-heavy areas and propose changes to reduce allocations."
  prompt_7="Review test runtime and suggest ways to cut CI time by at least 20%."
  prompt_8="Find frontend rendering bottlenecks and suggest measurable improvements."
  prompt_9="Locate duplicate work across services and propose consolidation opportunities."
  prompt_10="Review startup/init time and suggest one change to improve cold-start performance."

  idx=$((RANDOM % 10 + 1))
  selected_prompt_var="prompt_${idx}"
  selected_prompt="${!selected_prompt_var}"

  echo "Example prompt to try:" >&2
  echo "  ${selected_prompt}" >&2
  echo >&2
  echo "For detailed docs head to: https://cosine.sh/docs/cli" >&2
}

main "$@"
