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

release_base="${WANNALEAD_RELEASE_BASE_URL:-https://wannalead.co/releases/latest/download}"
extension_version="${WANNALEAD_EXTENSION_VERSION:-0.1.0}"
client_version="${WANNALEAD_CLIENT_VERSION:-$extension_version}"
package_url="${WANNALEAD_EXTENSION_PACKAGE_URL:-$release_base/wannalead-extension-$extension_version.zip}"
checksum_url="${WANNALEAD_EXTENSION_SHA256_URL:-$package_url.sha256}"
install_extension="${WANNALEAD_INSTALL_EXTENSION:-1}"
install_clients="${WANNALEAD_INSTALL_CLIENTS:-1}"
client_packages="${WANNALEAD_CLIENT_PACKAGES:-wannalead}"
open_chrome="${WANNALEAD_OPEN_CHROME:-1}"
reveal_folder="${WANNALEAD_REVEAL_EXTENSION_DIR:-1}"
copy_path="${WANNALEAD_COPY_EXTENSION_PATH:-1}"
allow_unverified="${WANNALEAD_ALLOW_UNVERIFIED_EXTENSION:-0}"
auto_load_unpacked="${WANNALEAD_AUTO_LOAD_UNPACKED:-1}"

need_command() {
  if ! command -v "$1" >/dev/null 2>&1; then
    echo "$1 is required" >&2
    exit 1
  fi
}

default_install_dir() {
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
    darwin)
      printf '%s\n' "$HOME/Library/Application Support/Wannalead/Chrome Extension"
      ;;
    linux)
      printf '%s\n' "${XDG_DATA_HOME:-$HOME/.local/share}/wannalead/chrome-extension"
      ;;
    msys*|mingw*|cygwin*)
      if [[ -n "${LOCALAPPDATA:-}" ]]; then
        printf '%s\n' "$LOCALAPPDATA/Wannalead/Chrome Extension"
      else
        printf '%s\n' "$HOME/AppData/Local/Wannalead/Chrome Extension"
      fi
      ;;
    *)
      echo "unsupported OS: $(uname -s)" >&2
      exit 1
      ;;
  esac
}

sha256_file() {
  if command -v shasum >/dev/null 2>&1; then
    shasum -a 256 "$1" | awk '{print $1}'
  elif command -v sha256sum >/dev/null 2>&1; then
    sha256sum "$1" | awk '{print $1}'
  else
    echo "shasum or sha256sum is required to verify the download" >&2
    exit 1
  fi
}

install_dir="${WANNALEAD_EXTENSION_INSTALL_DIR:-$(default_install_dir)}"

default_bin_dir() {
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
    msys*|mingw*|cygwin*)
      if [[ -n "${LOCALAPPDATA:-}" ]]; then
        printf '%s\n' "$LOCALAPPDATA/Wannalead/bin"
      else
        printf '%s\n' "$HOME/AppData/Local/Wannalead/bin"
      fi
      ;;
    *)
      printf '%s\n' "$HOME/.local/bin"
      ;;
  esac
}

bin_dir="${WANNALEAD_BIN_DIR:-$(default_bin_dir)}"

current_goos() {
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
    darwin) printf 'darwin\n' ;;
    linux) printf 'linux\n' ;;
    msys*|mingw*|cygwin*) printf 'windows\n' ;;
    *)
      echo "unsupported OS for Wannalead clients: $(uname -s)" >&2
      exit 1
      ;;
  esac
}

current_goarch() {
  case "$(uname -m | tr '[:upper:]' '[:lower:]')" in
    x86_64|amd64) printf 'amd64\n' ;;
    arm64|aarch64) printf 'arm64\n' ;;
    *)
      echo "unsupported CPU architecture for Wannalead clients: $(uname -m)" >&2
      exit 1
      ;;
  esac
}

validate_install_dir() {
  if [[ -z "$install_dir" || "$install_dir" == "/" || "$install_dir" == "$HOME" ]]; then
    echo "refusing unsafe extension install dir: $install_dir" >&2
    exit 1
  fi
  case "$install_dir" in
    "$HOME"/*|"$HOME"\\*) ;;
    *)
      echo "WANNALEAD_EXTENSION_INSTALL_DIR must be inside HOME" >&2
      exit 1
      ;;
  esac
  case "$install_dir" in
    *Wannalead*|*wannalead*) ;;
    *)
      echo "WANNALEAD_EXTENSION_INSTALL_DIR must include Wannalead in its path" >&2
      exit 1
      ;;
  esac
}

validate_bin_dir() {
  if [[ -z "$bin_dir" || "$bin_dir" == "/" || "$bin_dir" == "$HOME" ]]; then
    echo "refusing unsafe Wannalead bin dir: $bin_dir" >&2
    exit 1
  fi
  case "$bin_dir" in
    "$HOME"/*|"$HOME"\\*) ;;
    *)
      echo "WANNALEAD_BIN_DIR must be inside HOME" >&2
      exit 1
      ;;
  esac
}

download_checksum() {
  local checksum_file="$1"
  local expected=""

  if curl -fsSL "$checksum_url" -o "$checksum_file" 2>/dev/null; then
    expected="$(sed -n 's/^\([A-Fa-f0-9]\{64\}\).*/\1/p' "$checksum_file" | head -n 1 | tr '[:upper:]' '[:lower:]')"
  fi

  if [[ -n "$expected" ]]; then
    printf '%s\n' "$expected"
    return
  fi

  local manifest="$tmp/manifest.jsonl"
  if curl -fsSL "$release_base/manifest.jsonl" -o "$manifest" 2>/dev/null; then
    local file
    file="$(basename "$package_url")"
    local line
    line="$(
      grep "\"file\":\"$file\"" "$manifest" \
        | grep "\"name\":\"wannalead-extension\"" \
        | head -n 1 || true
    )"
    expected="$(printf '%s' "$line" | sed -n 's/.*"sha256":"\([A-Fa-f0-9]\{64\}\)".*/\1/p' | tr '[:upper:]' '[:lower:]')"
  fi

  printf '%s\n' "$expected"
}

validate_zip_entries() {
  local entries="$1"
  while IFS= read -r entry; do
    [[ -z "$entry" ]] && continue
    case "$entry" in
      /*|../*|*/../*|*/..|..)
        echo "refusing unsafe zip entry: $entry" >&2
        exit 1
        ;;
    esac
  done < "$entries"
}

validate_archive_entries() {
  local entries="$1"
  while IFS= read -r entry; do
    [[ -z "$entry" ]] && continue
    case "$entry" in
      /*|../*|*/../*|*/..|..)
        echo "refusing unsafe archive entry: $entry" >&2
        exit 1
        ;;
    esac
  done < "$entries"
}

download_expected_sha() {
  local url="$1"
  local checksum_file="$2"
  local expected=""
  if curl -fsSL "$url.sha256" -o "$checksum_file" 2>/dev/null; then
    expected="$(sed -n 's/^\([A-Fa-f0-9]\{64\}\).*/\1/p' "$checksum_file" | head -n 1 | tr '[:upper:]' '[:lower:]')"
  fi
  printf '%s\n' "$expected"
}

install_client_packages() {
  local goos goarch binary_ext
  goos="$(current_goos)"
  goarch="$(current_goarch)"
  binary_ext=""
  if [[ "$goos" == "windows" ]]; then
    binary_ext=".exe"
  fi

  mkdir -p "$bin_dir"
  echo "Installing Wannalead CLI/MCP client for $goos/$goarch..."

  local installed=()
  local package file url archive checksum_file entries extract_dir expected_sha actual_sha binary
  for package in $client_packages; do
    file="$package-$client_version-$goos-$goarch.tar.gz"
    url="$release_base/$file"
    archive="$tmp/$file"
    checksum_file="$tmp/$file.sha256"
    entries="$tmp/$file.entries"
    extract_dir="$tmp/$file.extract"
    binary="$package$binary_ext"

    rm -rf "$extract_dir"
    mkdir -p "$extract_dir"
    curl -fsSL "$url" -o "$archive"
    expected_sha="$(download_expected_sha "$url" "$checksum_file")"
    if [[ -z "$expected_sha" && "$allow_unverified" != "1" ]]; then
      echo "no checksum found for $url" >&2
      exit 1
    fi
    if [[ -n "$expected_sha" ]]; then
      actual_sha="$(sha256_file "$archive")"
      if [[ "$actual_sha" != "$expected_sha" ]]; then
        echo "checksum mismatch for $url" >&2
        exit 1
      fi
    fi
    tar -tzf "$archive" > "$entries"
    validate_archive_entries "$entries"
    tar -xzf "$archive" -C "$extract_dir"
    if [[ ! -f "$extract_dir/$binary" ]]; then
      echo "$file does not contain $binary" >&2
      exit 1
    fi
    install -m 0755 "$extract_dir/$binary" "$bin_dir/$binary"
    installed+=("$bin_dir/$binary")
  done

  echo "Installed Wannalead client binaries:"
  for binary in "${installed[@]}"; do
    echo "  $binary"
  done
  case ":$PATH:" in
    *":$bin_dir:"*) ;;
    *)
      echo "Add this to your shell profile if needed:"
      echo "  export PATH=\"$bin_dir:\$PATH\""
      ;;
  esac
}

copy_extension_path() {
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
    darwin)
      command -v pbcopy >/dev/null 2>&1 || return 1
      printf '%s' "$install_dir" | pbcopy
      ;;
    linux)
      command -v xclip >/dev/null 2>&1 || return 1
      printf '%s' "$install_dir" | xclip -selection clipboard
      ;;
    msys*|mingw*|cygwin*)
      command -v clip.exe >/dev/null 2>&1 || return 1
      printf '%s' "$install_dir" | clip.exe
      ;;
    *)
      return 1
      ;;
  esac
}

reveal_extension_dir() {
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
    darwin)
      open -R "$install_dir" >/dev/null 2>&1
      ;;
    linux)
      if command -v xdg-open >/dev/null 2>&1; then
        xdg-open "$(dirname "$install_dir")" >/dev/null 2>&1
      else
        return 1
      fi
      ;;
    msys*|mingw*|cygwin*)
      explorer.exe "$(cygpath -w "$install_dir" 2>/dev/null || printf '%s' "$install_dir")" >/dev/null 2>&1
      ;;
    *)
      return 1
      ;;
  esac
}

open_chrome_extensions_page() {
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
    darwin)
      open -b com.google.Chrome "chrome://extensions" >/dev/null 2>&1 \
        || open -a "Google Chrome" "chrome://extensions" >/dev/null 2>&1 \
        || open "chrome://extensions" >/dev/null 2>&1
      ;;
    linux)
      local chrome=""
      for candidate in google-chrome google-chrome-stable chromium chromium-browser brave-browser microsoft-edge; do
        if command -v "$candidate" >/dev/null 2>&1; then
          chrome="$candidate"
          break
        fi
      done
      [[ -n "$chrome" ]] || return 1
      (
        "$chrome" --new-tab "chrome://extensions" >/dev/null 2>&1 \
          || "$chrome" "chrome://extensions" >/dev/null 2>&1
      ) &
      ;;
    msys*|mingw*|cygwin*)
      cmd.exe /C start "" chrome "chrome://extensions" >/dev/null 2>&1
      ;;
    *)
      return 1
      ;;
  esac
}

automate_macos_load_unpacked() {
  case "$(uname -s | tr '[:upper:]' '[:lower:]')" in
    darwin) ;;
    *) return 1 ;;
  esac
  command -v osascript >/dev/null 2>&1 || return 1

  local script_file="$tmp/wannalead-load-unpacked.applescript"
  cat > "$script_file" <<'APPLESCRIPT'
on run argv
  set extensionPath to item 1 of argv

  tell application "Google Chrome"
    activate
  end tell
  delay 1

  tell application "System Events"
    if UI elements enabled is false then
      error "Accessibility access is not enabled for this terminal."
    end if
    tell process "Google Chrome"
      set frontmost to true
      delay 0.5
      if my clickLoadUnpacked(window 1) is false then
        try
          set winPos to position of window 1
          click at {((item 1 of winPos) + 190), ((item 2 of winPos) + 155)}
        end try
      end if
    end tell

    delay 0.8
    set the clipboard to extensionPath
    keystroke "g" using {command down, shift down}
    delay 0.4
    keystroke "v" using {command down}
    delay 0.2
    key code 36
    delay 0.8
    key code 36
  end tell
end run

on clickLoadUnpacked(rootElement)
  tell application "System Events"
    try
      set elementName to name of rootElement as text
      if elementName contains "Load unpacked" or elementName contains "extension non empaquet" then
        click rootElement
        return true
      end if
    end try
    try
      repeat with childElement in UI elements of rootElement
        if my clickLoadUnpacked(childElement) then return true
      end repeat
    end try
  end tell
  return false
end clickLoadUnpacked
APPLESCRIPT

  osascript "$script_file" "$install_dir"
}

need_command curl
if [[ "$install_extension" != "0" ]]; then
  need_command unzip
  validate_install_dir
fi
if [[ "$install_clients" != "0" ]]; then
  need_command tar
  validate_bin_dir
fi

tmp="$(mktemp -d)"
cleanup() {
  rm -rf "$tmp"
}
trap cleanup EXIT

archive="$tmp/wannalead-extension.zip"
checksum_file="$tmp/wannalead-extension.zip.sha256"
entries="$tmp/entries.txt"
extract_dir="$tmp/extract"
parent="$(dirname "$install_dir")"
name="$(basename "$install_dir")"
staging="$parent/.${name}.new.$$"
backup="$parent/.${name}.previous.$$"

if [[ "$install_extension" != "0" ]]; then
  mkdir -p "$parent"
  rm -rf "$staging" "$backup"
  mkdir -p "$staging" "$extract_dir"

  echo "Downloading Wannalead extension package..."
  curl -fsSL "$package_url" -o "$archive"

  expected_sha="$(download_checksum "$checksum_file")"
  if [[ -z "$expected_sha" && "$allow_unverified" != "1" ]]; then
    echo "no checksum found for $package_url" >&2
    echo "publish $checksum_url or set WANNALEAD_ALLOW_UNVERIFIED_EXTENSION=1 for local testing" >&2
    exit 1
  fi
  if [[ -n "$expected_sha" ]]; then
    actual_sha="$(sha256_file "$archive")"
    if [[ "$actual_sha" != "$expected_sha" ]]; then
      echo "checksum mismatch for $package_url" >&2
      exit 1
    fi
  fi

  unzip -Z1 "$archive" > "$entries"
  validate_zip_entries "$entries"
  unzip -q "$archive" -d "$extract_dir"

  package_root="$extract_dir"
  if [[ ! -f "$package_root/manifest.json" ]]; then
    manifest_path="$(find "$extract_dir" -mindepth 2 -maxdepth 2 -name manifest.json -print -quit)"
    if [[ -z "$manifest_path" ]]; then
      echo "extension package does not contain manifest.json" >&2
      exit 1
    fi
    package_root="$(dirname "$manifest_path")"
  fi

  cp -R "$package_root"/. "$staging"/
  if [[ ! -f "$staging/manifest.json" ]]; then
    echo "extension manifest missing after install staging" >&2
    exit 1
  fi
  if ! grep -q '"name"[[:space:]]*:[[:space:]]*"Wannalead"' "$staging/manifest.json"; then
    echo "extension manifest is not Wannalead" >&2
    exit 1
  fi

  if [[ -e "$install_dir" ]]; then
    mv "$install_dir" "$backup"
  fi
  mv "$staging" "$install_dir"
  rm -rf "$backup"

  echo "Installed Wannalead extension files:"
  echo "  $install_dir"

  if [[ "$copy_path" != "0" ]]; then
    if copy_extension_path; then
      echo "Copied extension folder path to the clipboard."
    fi
  fi

  if [[ "$reveal_folder" != "0" ]]; then
    reveal_extension_dir || true
  fi

  if [[ "$open_chrome" != "0" ]]; then
    if open_chrome_extensions_page; then
      echo "Opened chrome://extensions in Chrome."
      if [[ "$auto_load_unpacked" != "0" ]]; then
        if automate_macos_load_unpacked; then
          echo "Attempted to select the Wannalead extension folder in Chrome."
        else
          echo "Could not automate Load unpacked; finish the Chrome step manually."
        fi
      fi
    else
      echo "Could not open Chrome automatically; open chrome://extensions manually."
    fi
  fi
fi

if [[ "$install_clients" != "0" ]]; then
  install_client_packages
fi

if [[ "$install_extension" != "0" ]]; then
  cat <<EOF

Finish in Chrome:
  1. Enable Developer mode in chrome://extensions.
  2. Click "Load unpacked".
  3. Select this exact folder:
     $install_dir
  4. Open the Wannalead extension and click "Connect".

If Chrome's folder picker opens somewhere else, do not select the current
folder. On macOS, press Command-Shift-G, paste the copied folder path, press
Return, then click Select.
EOF
fi
