#!/usr/bin/env bash
# Luckin CLI 安装脚本（macOS / Linux）
# curl -fsSL ${LUCKIN_AUTH_BASE_URL}/install | bash
# Windows: irm ${LUCKIN_AUTH_BASE_URL}/window/install | iex
if [ -z "${BASH_VERSION:-}" ]; then
	exec bash "$0" "$@"
fi
set -uo pipefail

# 环境 URL 内联于此，与 internal/env/definitions.go、scripts/profile.sh 保持一致。
# curl | bash 时无法 source 外部 profile.sh，故不可依赖同目录文件。
# 本常量决定默认 manifest；测试3 / 生产各部署一份（生产见 scripts/gen-install-scripts.sh）。
LUCKIN_AUTH_BASE_DEFAULT='https://open.lkcoffee.com'

load_luckin_env() {
	local _luckin_auth_base="${LUCKIN_AUTH_BASE_URL:-}"

	if [ -z "$_luckin_auth_base" ]; then
		if [ -n "${LUCKIN_PROFILE:-}" ]; then
			case "$LUCKIN_PROFILE" in
			dev | test3 | test | test03)
				_luckin_auth_base="https://opentest03.lkcoffee.com"
				;;
			prod)
				_luckin_auth_base="https://open.lkcoffee.com"
				;;
			*)
				printf '未知 LUCKIN_PROFILE=%s（支持 dev test3 prod）\n' "$LUCKIN_PROFILE" >&2
				exit 1
				;;
			esac
		else
			_luckin_auth_base="$LUCKIN_AUTH_BASE_DEFAULT"
		fi
	fi
	_luckin_auth_base="${_luckin_auth_base%/}"

	case "$_luckin_auth_base" in
	https://open.lkcoffee.com) export LUCKIN_PROFILE=prod ;;
	*) export LUCKIN_PROFILE=test3 ;;
	esac
	export LUCKIN_AUTH_BASE_URL="$_luckin_auth_base"
	export LUCKIN_BASE_URL="${LUCKIN_BASE_URL:-$_luckin_auth_base/cli}"
	export LUCKIN_MANIFEST_PUBLIC_URL="${LUCKIN_MANIFEST_PUBLIC_URL:-$_luckin_auth_base/cli/manifest.json}"
	export LUCKIN_MANIFEST_URL="${LUCKIN_MANIFEST_URL:-$_luckin_auth_base/cli/manifest.json}"
}

load_luckin_env
BASE_URL="${LUCKIN_BASE_URL}"
INSTALL_ENTRY_URL="${LUCKIN_AUTH_BASE_URL}/install"
# 安装脚本默认覆盖已有安装（与 irm|iex / npm postinstall 行为一致）
FORCE=1

export LUCKIN_CLI_INSTALL=1

usage() {
	cat <<EOF >&2
Luckin CLI Installation Script

USAGE:
  curl -fsSL ${INSTALL_ENTRY_URL} | bash
  curl -fsSL ${INSTALL_ENTRY_URL} | bash -s -- [OPTIONS]

OPTIONS:
  --no-force  已有安装时不覆盖（默认会覆盖）
  --force     同默认行为，显式覆盖已有安装
  -h, --help  显示帮助
EOF
}

while [[ $# -gt 0 ]]; do
	case "$1" in
	-h | --help)
		usage
		exit 0
		;;
	--no-force)
		FORCE=0
		shift
		;;
	--force)
		FORCE=1
		shift
		;;
	*)
		echo "Error: Unknown option $1" >&2
		usage
		exit 1
		;;
	esac
done

require_cmd() {
	if ! command -v "$1" >/dev/null 2>&1; then
		echo "Error: $1 is required but not installed" >&2
		exit 1
	fi
}

fatal_error() {
	echo "" >&2
	echo "Fatal Error: $1" >&2
	if [[ $# -gt 1 ]]; then
		shift
		echo "" >&2
		for suggestion in "$@"; do
			echo "  - $suggestion" >&2
		done
	fi
	echo "" >&2
	exit 1
}

download() {
	local url="$1" output="$2"
	local max_retries=3 retry_count=0

	while [[ $retry_count -lt $max_retries ]]; do
		[[ $retry_count -gt 0 ]] && sleep 2

		if command -v curl >/dev/null 2>&1; then
			if [[ -n "${LUCKIN_DOWNLOAD_TOKEN:-}" ]]; then
				if curl -fsSL --retry 2 --connect-timeout 30 --max-time 300 \
					-H "User-Agent: luckin-cli-installer/curl-bash" \
					-H "Authorization: Bearer ${LUCKIN_DOWNLOAD_TOKEN}" \
					"$url" -o "$output"; then
					return 0
				fi
			elif curl -fsSL --retry 2 --connect-timeout 30 --max-time 300 \
				-H "User-Agent: luckin-cli-installer/curl-bash" \
				"$url" -o "$output"; then
				return 0
			fi
		elif command -v wget >/dev/null 2>&1; then
			if [[ -n "${LUCKIN_DOWNLOAD_TOKEN:-}" ]]; then
				if wget -q --tries=2 --connect-timeout=30 --read-timeout=300 \
					--header="Authorization: Bearer ${LUCKIN_DOWNLOAD_TOKEN}" \
					--user-agent="luckin-cli-installer/curl-bash" \
					"$url" -O "$output"; then
					return 0
				fi
			elif wget -q --tries=2 --connect-timeout=30 --read-timeout=300 \
				--user-agent="luckin-cli-installer/curl-bash" \
				"$url" -O "$output"; then
				return 0
			fi
		else
			echo "Error: Neither curl nor wget is available" >&2
			exit 1
		fi

		rm -f "$output" 2>/dev/null || true
		retry_count=$((retry_count + 1))
	done
	return 1
}

detect_os_arch() {
	local os arch
	os="$(uname -s | tr '[:upper:]' '[:lower:]')"
	arch="$(uname -m)"

	if [[ "$os" == "darwin" && "$arch" == "x86_64" ]]; then
		if sysctl -n hw.optional.arm64 2>/dev/null | grep -q '1'; then
			arch="arm64"
			echo "==> Detected Apple Silicon (Rosetta); selecting arm64 binary" >&2
		fi
	fi

	[[ "$arch" == "aarch64" ]] && arch="arm64"
	[[ "$arch" == "x86_64" ]] && arch="amd64"

	echo "$os $arch"
}

TMP_DIR=""
cleanup() {
	if [[ -n "$TMP_DIR" && -d "$TMP_DIR" ]]; then
		rm -rf "$TMP_DIR" 2>/dev/null || true
	fi
}

main() {
	local os_name
	os_name="$(uname -s | tr '[:upper:]' '[:lower:]')"
	if [[ "$os_name" == *"mingw"* || "$os_name" == *"cygwin"* || "$os_name" == *"msys"* ]]; then
		echo "Windows detected. Use PowerShell:" >&2
		echo "  irm \"${LUCKIN_AUTH_BASE_URL}/window/install\" | iex" >&2
		exit 1
	fi

	TMP_DIR="$(mktemp -d -t luckin-install.XXXXXX)"
	trap cleanup EXIT INT TERM

	local os arch
	read -r os arch < <(detect_os_arch)

	if [[ "$os" != "darwin" && "$os" != "linux" ]]; then
		fatal_error "Unsupported OS: $os"
	fi

	echo "==> Platform: $os/$arch"

	local manifest_url="${LUCKIN_MANIFEST_URL:-$LUCKIN_MANIFEST_PUBLIC_URL}"
	[[ -z "$manifest_url" ]] && fatal_error "请设置 LUCKIN_MANIFEST_URL 或 LUCKIN_MANIFEST_PUBLIC_URL"
	local manifest_file="$TMP_DIR/manifest.json"

	echo "==> Fetching release information..."
	if ! download "$manifest_url" "$manifest_file"; then
		fatal_error "Failed to download manifest from $manifest_url"
	fi

	local manifest_json
	manifest_json="$(cat "$manifest_file")"

	local version
	version=$(printf '%s' "$manifest_json" | sed -n 's/.*"latest"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
	[[ -z "$version" ]] && fatal_error "Cannot parse version from manifest"

	echo "==> Latest version: $version"

	local entry
	entry=$(printf '%s' "$manifest_json" | tr -d '\n\r\t ' | sed 's/},{/}\n{/g' | grep -F "\"os\":\"$os\"" | grep -F "\"arch\":\"$arch\"" | head -n1)
	[[ -z "$entry" ]] && fatal_error "No binary available for $os/$arch"

	local download_url checksum
	download_url=$(printf '%s' "$entry" | sed -n 's/.*"url"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
	checksum=$(printf '%s' "$entry" | sed -n 's/.*"sha256"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p')
	[[ -z "$download_url" ]] && fatal_error "Missing download URL in manifest for $os/$arch"

	echo "==> Downloading Luckin CLI $version..."
	local archive_kind archive_file
	if [[ "$os" == "windows" || "$download_url" =~ \.zip$ ]]; then
		archive_kind=zip
		archive_file="$TMP_DIR/luckin.zip"
		require_cmd unzip
	else
		archive_kind=tgz
		archive_file="$TMP_DIR/luckin.tar.gz"
		require_cmd tar
	fi

	if ! download "$download_url" "$archive_file"; then
		fatal_error "Failed to download binary from $download_url"
	fi

	local file_size
	file_size=$(wc -c <"$archive_file" 2>/dev/null || echo "0")
	[[ "$file_size" -lt 1024 ]] && fatal_error "Download too small ($file_size bytes), likely corrupted"

	if [[ -n "$checksum" ]]; then
		echo "==> Verifying checksum..."
		local actual_checksum=""
		if command -v shasum >/dev/null 2>&1; then
			actual_checksum=$(shasum -a 256 "$archive_file" | cut -d' ' -f1)
		elif command -v sha256sum >/dev/null 2>&1; then
			actual_checksum=$(sha256sum "$archive_file" | cut -d' ' -f1)
		fi
		if [[ -n "$actual_checksum" && "$actual_checksum" != "$checksum" ]]; then
			fatal_error "Checksum mismatch" "Expected: $checksum" "Actual: $actual_checksum"
		fi
		echo "==> Checksum verified"
	fi

	echo "==> Extracting..."
	local extract_dir="$TMP_DIR/extract"
	mkdir -p "$extract_dir"

	if [[ "$archive_kind" == "zip" ]]; then
		unzip -q "$archive_file" -d "$extract_dir" || fatal_error "Failed to extract zip"
	else
		tar -xzf "$archive_file" -C "$extract_dir" || fatal_error "Failed to extract tar.gz"
	fi

	local bin_name="luckin"
	[[ ! -f "$extract_dir/$bin_name" ]] && fatal_error "Binary $bin_name not found in archive"
	local bin_size
	bin_size=$(wc -c <"$extract_dir/$bin_name" | tr -d ' ')
	[[ "$bin_size" -lt 1 ]] && fatal_error "Binary $bin_name is empty"
	chmod +x "$extract_dir/$bin_name"

	echo "==> Installing..."
	local install_args=(install)
	if [[ "$FORCE" -eq 1 ]]; then
		install_args+=(--force)
	else
		echo "==> 保留已有安装（未使用 --force）" >&2
	fi
	if ! "$extract_dir/$bin_name" "${install_args[@]}"; then
		fatal_error "Install subcommand failed"
	fi
}

main "$@"
