#!/bin/sh
set -e

REPO="${REPO:-Awenforever/weclaw_dev}"
BINARY="${BINARY:-weclaw}"
INSTALL_DIR="${INSTALL_DIR:-/usr/local/bin}"
VERSION="${VERSION:-}"
REF="${REF:-main}"
GO_BOOTSTRAP_VERSION="${GO_BOOTSTRAP_VERSION:-1.25.0}"
ACTION="install"
TMP_ROOT=""
INSTALL_SKIPPED_ALREADY_CURRENT=0

usage() {
  cat <<'USAGE'
WeClaw Dev installer

Usage:
  sh install.sh
  sh install.sh --uninstall

Options:
  --version VERSION     Install a specific GitHub Release tag
  --install-dir DIR     Install directory, default: /usr/local/bin
  --repo OWNER/REPO     GitHub repository, default: Awenforever/weclaw_dev
  --ref REF             Source build ref, default: main
  --uninstall           Remove the installed weclaw binary and keep ~/.weclaw data
  --help                Show this help

Examples:
  # Stable/latest channel:
  curl -fsSL https://cdn.jsdelivr.net/gh/Awenforever/weclaw_dev@main/install.sh | sh
  # Fallback:
  curl -fsSL https://raw.githubusercontent.com/Awenforever/weclaw_dev/main/install.sh | sh

  # Pre-release/pinned install:
  curl -fsSL https://raw.githubusercontent.com/Awenforever/weclaw_dev/v0.1.9-alpha/install.sh | sh -s -- --version v0.1.9-alpha

  curl -fsSL https://cdn.jsdelivr.net/gh/Awenforever/weclaw_dev@main/install.sh | sh -s -- --uninstall
  # Fallback:
  curl -fsSL https://raw.githubusercontent.com/Awenforever/weclaw_dev/main/install.sh | sh -s -- --uninstall
USAGE
}

parse_args() {
  while [ "$#" -gt 0 ]; do
    case "$1" in
      --help|-h)
        ACTION="help"
        ;;
      --uninstall|uninstall)
        ACTION="uninstall"
        ;;
      --version)
        shift
        if [ "$#" -eq 0 ]; then
          echo "Error: --version requires a value"
          return 1
        fi
        VERSION="$1"
        ;;
      --version=*)
        VERSION="${1#--version=}"
        ;;
      --install-dir)
        shift
        if [ "$#" -eq 0 ]; then
          echo "Error: --install-dir requires a value"
          return 1
        fi
        INSTALL_DIR="$1"
        ;;
      --install-dir=*)
        INSTALL_DIR="${1#--install-dir=}"
        ;;
      --repo)
        shift
        if [ "$#" -eq 0 ]; then
          echo "Error: --repo requires a value"
          return 1
        fi
        REPO="$1"
        ;;
      --repo=*)
        REPO="${1#--repo=}"
        ;;
      --ref)
        shift
        if [ "$#" -eq 0 ]; then
          echo "Error: --ref requires a value"
          return 1
        fi
        REF="$1"
        ;;
      --ref=*)
        REF="${1#--ref=}"
        ;;
      *)
        echo "Error: unknown option: $1"
        usage
        return 1
        ;;
    esac
    shift
  done
}

cleanup_tmp() {
  if [ -n "$TMP_ROOT" ] && [ -d "$TMP_ROOT" ]; then
    rm -rf "$TMP_ROOT"
  fi
}

resolve_tool() {
  tool="$1"

  if command -v "$tool" >/dev/null 2>&1; then
    command -v "$tool"
    return 0
  fi

  for shell_bin in bash zsh; do
    if command -v "$shell_bin" >/dev/null 2>&1; then
      resolved=$("$shell_bin" -lc "command -v $tool" 2>/dev/null || true)
      if [ -n "$resolved" ] && [ -x "$resolved" ]; then
        printf '%s\n' "$resolved"
        return 0
      fi
    fi
  done

  case "$tool" in
    go)
      for candidate in /usr/local/go/bin/go /opt/homebrew/bin/go /usr/local/bin/go; do
        if [ -x "$candidate" ]; then
          printf '%s\n' "$candidate"
          return 0
        fi
      done
      ;;
    git)
      for candidate in /usr/bin/git /usr/local/bin/git /opt/homebrew/bin/git; do
        if [ -x "$candidate" ]; then
          printf '%s\n' "$candidate"
          return 0
        fi
      done
      ;;
  esac

  return 1
}

detect_platform() {
  OS=$(uname -s | tr '[:upper:]' '[:lower:]')
  case "$OS" in
    darwin|linux) ;;
    *)
      echo "Unsupported OS: $OS"
      return 1
      ;;
  esac

  ARCH=$(uname -m)
  case "$ARCH" in
    x86_64|amd64) ARCH="amd64" ;;
    aarch64|arm64) ARCH="arm64" ;;
    *)
      echo "Unsupported architecture: $ARCH"
      return 1
      ;;
  esac

  echo "Detected: ${OS}/${ARCH}"
}

ensure_tmp_root() {
  if [ -z "$TMP_ROOT" ]; then
    TMP_ROOT=$(mktemp -d 2>/dev/null || mktemp -d -t weclaw-install)
  fi
}

install_binary_file() {
  src="$1"
  target="${INSTALL_DIR}/${BINARY}"
  staged="${INSTALL_DIR}/.${BINARY}-install-$$.new"

  if [ ! -f "$src" ]; then
    echo "Error: binary source not found: ${src}" >&2
    return 1
  fi

  chmod +x "$src" || return 1

  if [ -d "$INSTALL_DIR" ] && [ -w "$INSTALL_DIR" ]; then
    cp "$src" "$staged"
    chmod +x "$staged"
    mv -f "$staged" "$target"
  else
    echo "Installing to ${INSTALL_DIR} (requires sudo)..."
    sudo mkdir -p "$INSTALL_DIR"
    sudo cp "$src" "$staged"
    sudo chmod +x "$staged"
    sudo mv -f "$staged" "$target"
  fi
}

fetch_release_version() {
  curl -fsSL -H "User-Agent: weclaw-installer" "https://api.github.com/repos/${REPO}/releases/latest" | sed -n 's/.*"tag_name" *: *"\([^"]*\)".*/\1/p'
}


installed_binary_version() {
  target="${INSTALL_DIR}/${BINARY}"
  if [ ! -x "$target" ]; then
    return 1
  fi

  "$target" version 2>/dev/null | sed -n 's/.*\(v[0-9][0-9A-Za-z._-]*\).*/\1/p' | head -n 1
}


curl_fetch() {
  FETCH_URL="$1"
  FETCH_DEST="$2"
  FETCH_LABEL="$3"

  rm -f "$FETCH_DEST"
  curl -fL \
    --retry 8 \
    --retry-delay 2 \
    --connect-timeout 20 \
    --max-time 300 \
    "$FETCH_URL" \
    -o "$FETCH_DEST"
  FETCH_STATUS="$?"

  if [ "$FETCH_STATUS" = "0" ] && [ -s "$FETCH_DEST" ]; then
    return 0
  fi

  echo "${FETCH_LABEL} download failed with curl status ${FETCH_STATUS}: ${FETCH_URL}" >&2
  rm -f "$FETCH_DEST"
  return "$FETCH_STATUS"
}


install_release() {
  echo "Fetching latest release..."
  if [ -z "$VERSION" ]; then
    VERSION=$(fetch_release_version || true)
  fi
  if [ -z "$VERSION" ]; then
    return 1
  fi

  echo "Latest version: ${VERSION}"

  INSTALL_SKIPPED_ALREADY_CURRENT=0
  INSTALLED_VERSION=$(installed_binary_version || true)
  if [ -n "$INSTALLED_VERSION" ] && [ "$INSTALLED_VERSION" = "$VERSION" ]; then
    INSTALL_SKIPPED_ALREADY_CURRENT=1
    echo "weclaw ${VERSION} is already installed at ${INSTALL_DIR}/${BINARY}; skipping download."
    return 0
  fi

  FILENAME="${BINARY}_${OS}_${ARCH}"
  URL="https://github.com/${REPO}/releases/download/${VERSION}/${FILENAME}"

  ensure_tmp_root
  TMP="${TMP_ROOT}/${FILENAME}"

  echo "Downloading ${URL}..."
  curl_fetch "$URL" "$TMP" "Release asset"
  ASSET_STATUS="$?"
  if [ "$ASSET_STATUS" != "0" ]; then
    rm -f "$TMP"
    if [ "$ASSET_STATUS" = "22" ]; then
      echo "No release asset found at ${URL}; building from source..."
    else
      echo "Release asset download failed due to network or transport error; trying source fallback..."
    fi
    return 1
  fi

  chmod +x "$TMP"
  install_binary_file "$TMP"
}


download_go_toolchain() {
  if ! command -v tar >/dev/null 2>&1; then
    echo "Error: tar is required to bootstrap Go." >&2
    return 1
  fi

  ensure_tmp_root
  GO_OS="$OS"
  GO_ARCH="$ARCH"
  PRIMARY_URL="https://go.dev/dl/go${GO_BOOTSTRAP_VERSION}.${GO_OS}-${GO_ARCH}.tar.gz"
  FALLBACK_URL="https://dl.google.com/go/go${GO_BOOTSTRAP_VERSION}.${GO_OS}-${GO_ARCH}.tar.gz"
  ARCHIVE="${TMP_ROOT}/go-bootstrap.tar.gz"
  DEST="${TMP_ROOT}/go-bootstrap"

  echo "Go not found or system Go is unsuitable; bootstrapping Go ${GO_BOOTSTRAP_VERSION}." >&2
  rm -rf "$DEST" "$ARCHIVE"
  mkdir -p "$DEST"

  echo "Downloading Go toolchain from ${PRIMARY_URL}..." >&2
  if ! curl_fetch "$PRIMARY_URL" "$ARCHIVE" "Go toolchain"; then
    echo "Primary Go toolchain download failed; trying fallback: ${FALLBACK_URL}" >&2
    if ! curl_fetch "$FALLBACK_URL" "$ARCHIVE" "Go toolchain fallback"; then
      echo "Error: failed to download Go toolchain from go.dev or dl.google.com." >&2
      return 1
    fi
  fi

  if ! tar -C "$DEST" -xzf "$ARCHIVE"; then
    echo "Error: failed to extract bootstrapped Go toolchain." >&2
    return 1
  fi

  if [ ! -x "$DEST/go/bin/go" ]; then
    echo "Error: bootstrapped Go toolchain is invalid." >&2
    return 1
  fi

  printf '%s\n' "$DEST/go/bin/go"
}

install_from_source() {
  ensure_tmp_root
  SRC="${TMP_ROOT}/src"
  SRC_ROOT="${TMP_ROOT}/source-root"
  SRC_ARCHIVE="${TMP_ROOT}/source.tar.gz"

  rm -rf "$SRC" "$SRC_ROOT" "$SRC_ARCHIVE"
  mkdir -p "$SRC_ROOT"

  echo "Building from source fallback..."

  if [ -n "$VERSION" ]; then
    SRC_URL="https://codeload.github.com/${REPO}/tar.gz/refs/tags/${VERSION}"
    echo "Trying source tarball: ${SRC_URL}"
    curl_fetch "$SRC_URL" "$SRC_ARCHIVE" "Source tarball" || true
  fi

  if [ ! -s "$SRC_ARCHIVE" ]; then
    SRC_URL="https://codeload.github.com/${REPO}/tar.gz/refs/heads/${REF}"
    echo "Trying source ref tarball: ${SRC_URL}"
    curl_fetch "$SRC_URL" "$SRC_ARCHIVE" "Source ref tarball" || true
  fi

  if [ -s "$SRC_ARCHIVE" ]; then
    tar -xzf "$SRC_ARCHIVE" -C "$SRC_ROOT"
    SRC_EXTRACTED=$(find "$SRC_ROOT" -mindepth 1 -maxdepth 1 -type d | head -n 1)
    if [ -z "$SRC_EXTRACTED" ]; then
      echo "Error: source tarball extraction produced no source directory." >&2
      return 1
    fi
    mv "$SRC_EXTRACTED" "$SRC"
  else
    GIT_BIN=$(resolve_tool git || true)
    if [ -z "$GIT_BIN" ]; then
      echo "Error: source tarball fallback failed and git is not available." >&2
      return 1
    fi

    echo "Source tarball fallback failed; trying git clone over HTTP/1.1 as last resort..."
    if [ -n "$VERSION" ]; then
      "$GIT_BIN" -c http.version=HTTP/1.1 clone --depth 1 --branch "$VERSION" "https://github.com/${REPO}.git" "$SRC" \
        || "$GIT_BIN" -c http.version=HTTP/1.1 clone --depth 1 --branch "$REF" "https://github.com/${REPO}.git" "$SRC"
    else
      "$GIT_BIN" -c http.version=HTTP/1.1 clone --depth 1 --branch "$REF" "https://github.com/${REPO}.git" "$SRC"
    fi
  fi

  if [ ! -d "$SRC" ]; then
    echo "Error: source fallback failed before build." >&2
    return 1
  fi

  GO_BIN=$(download_go_toolchain)
  if [ -z "$GO_BIN" ] || [ ! -x "$GO_BIN" ]; then
    echo "Error: failed to prepare Go toolchain." >&2
    return 1
  fi

  BUILD_PUBLIC_VERSION="${VERSION:-source}"
  BUILD_PUBLIC_COMMIT="${BUILD_PUBLIC_COMMIT:-unknown}"
  BUILD_INTERNAL_VERSION="${BUILD_INTERNAL_VERSION:-source}"
  BUILD_INTERNAL_COMMIT="${BUILD_INTERNAL_COMMIT:-unknown}"
  if ! (
    cd "$SRC"
    CGO_ENABLED=0 "$GO_BIN" build -trimpath \
      -ldflags="-s -w -X github.com/fastclaw-ai/weclaw/cmd.Version=${BUILD_PUBLIC_VERSION} -X github.com/fastclaw-ai/weclaw/cmd.PublicCommit=${BUILD_PUBLIC_COMMIT} -X github.com/fastclaw-ai/weclaw/cmd.InternalVersion=${BUILD_INTERNAL_VERSION} -X github.com/fastclaw-ai/weclaw/cmd.InternalCommit=${BUILD_INTERNAL_COMMIT}" \
      -o "${TMP_ROOT}/${BINARY}" .
  ); then
    echo "Error: source build failed." >&2
    return 1
  fi

  if [ ! -x "${TMP_ROOT}/${BINARY}" ]; then
    echo "Error: source build did not produce ${TMP_ROOT}/${BINARY}." >&2
    return 1
  fi

  install_binary_file "${TMP_ROOT}/${BINARY}"
}

uninstall_binary() {
  target="${INSTALL_DIR}/${BINARY}"
  resolved=$(command -v "$BINARY" 2>/dev/null || true)
  if [ -n "$resolved" ]; then
    target="$resolved"
  fi

  if [ ! -e "$target" ]; then
    echo "weclaw binary not found at ${target}"
    echo "User data, if any, remains at ~/.weclaw"
    return 0
  fi

  echo "Removing ${target}..."
  if rm -f "$target" 2>/dev/null; then
    echo "weclaw binary removed."
  else
    echo "Removing ${target} requires sudo..."
    sudo rm -f "$target"
    echo "weclaw binary removed."
  fi

  echo "User data is preserved at ~/.weclaw"
  echo "To reinstall:"
  echo "  curl -fsSL https://cdn.jsdelivr.net/gh/${REPO}@main/install.sh | sh"
  echo "  # Fallback:"
  echo "  curl -fsSL https://raw.githubusercontent.com/${REPO}/main/install.sh | sh"
}

main() {
  parse_args "$@" || return 1

  if [ "$ACTION" = "help" ]; then
    usage
    return 0
  fi

  if [ "$ACTION" = "uninstall" ]; then
    uninstall_binary
    return $?
  fi

  trap cleanup_tmp 0 2 3 15

  detect_platform || return 1

  if ! install_release; then
    install_from_source || return 1
  fi

  if [ "$OS" = "darwin" ]; then
    xattr -d com.apple.quarantine "${INSTALL_DIR}/${BINARY}" 2>/dev/null || true
    xattr -d com.apple.provenance "${INSTALL_DIR}/${BINARY}" 2>/dev/null || true
  fi

  echo ""
  if [ "$INSTALL_SKIPPED_ALREADY_CURRENT" = "1" ]; then
    echo "weclaw ${VERSION} already installed at ${INSTALL_DIR}/${BINARY}"
  elif [ -n "$VERSION" ]; then
    echo "weclaw ${VERSION} installed to ${INSTALL_DIR}/${BINARY}"
  else
    echo "weclaw installed to ${INSTALL_DIR}/${BINARY}"
  fi
  echo ""
  echo "Get started:"
  echo "  weclaw start"
  echo "  weclaw start --stdout"
  echo ""
  echo "Update later:"
  echo "  weclaw upgrade"
  echo "  weclaw upgrade --alpha"
  echo "  curl -fsSL https://cdn.jsdelivr.net/gh/${REPO}@main/install.sh | sh"
  echo "  # Pre-release/pinned install example:"
  echo "  curl -fsSL https://raw.githubusercontent.com/${REPO}/v0.1.9-alpha/install.sh | sh -s -- --version v0.1.9-alpha"
  echo "  # Fallback:"
  echo "  curl -fsSL https://raw.githubusercontent.com/${REPO}/main/install.sh | sh"
  echo ""
  echo "Uninstall:"
  echo "  curl -fsSL https://cdn.jsdelivr.net/gh/${REPO}@main/install.sh | sh -s -- --uninstall"
  echo "  # Fallback:"
  echo "  curl -fsSL https://raw.githubusercontent.com/${REPO}/main/install.sh | sh -s -- --uninstall"
}

main "$@"
