#!/usr/bin/env bash
#
# CloudRadial AutomationAI - runner prerequisite installer (macOS)
#
# Installs every local tool a Mac needs to install, scale, and upgrade an
# AutomationAI runner:
#
#   - PowerShell 7           (Homebrew formula: powershell)
#   - Azure CLI              (Homebrew formula: azure-cli)
#   - Bicep CLI              (official Microsoft binary -> /usr/local/bin/bicep)
#   - Az PowerShell modules  (Az.Accounts, Az.Resources, Az.KeyVault,
#                             Az.Websites, Az.CognitiveServices)
#
# Anything already present is left alone unless --force is passed. Safe to
# re-run. It does NOT sign you in to Azure and does NOT deploy anything.
#
# Usage:
#   chmod +x ./install-runner-prereqs-macos.sh
#   ./install-runner-prereqs-macos.sh [--skip-az-modules] [--force] [--yes]
#
#   --skip-az-modules  Install the command-line tools only. The runner installer
#                      auto-installs the Az submodules it needs on first run.
#   --force            Reinstall/upgrade even when a tool is already present.
#   --yes              Do not prompt. Installs Homebrew automatically if missing.
#
# Requires macOS 13 or later (the Azure CLI Homebrew formula's floor).
# Some steps use sudo and will prompt for your password.

set -euo pipefail

SKIP_AZ_MODULES=0
FORCE=0
ASSUME_YES=0

# Az submodules the runner install/upgrade scripts actually load. Keep in step
# with infra/runner-sample/Deploy-Runner.ps1.
AZ_MODULES="'Az.Accounts','Az.Resources','Az.KeyVault','Az.Websites','Az.CognitiveServices'"

BICEP_INSTALL_PATH="/usr/local/bin/bicep"

while [ $# -gt 0 ]; do
  case "$1" in
    --skip-az-modules) SKIP_AZ_MODULES=1 ;;
    --force)           FORCE=1 ;;
    --yes|-y)          ASSUME_YES=1 ;;
    -h|--help)
      # Print the header comment block and stop at the first non-comment line,
      # so the help text can't drift out of sync with a hard-coded line range.
      awk 'NR>1 && /^#/ { sub(/^# ?/, ""); print; next } NR>1 { exit }' "$0"
      exit 0
      ;;
    *)
      echo "Unknown option: $1" >&2
      echo "Usage: $0 [--skip-az-modules] [--force] [--yes]" >&2
      exit 2
      ;;
  esac
  shift
done

step() { printf '\n==== %s ====\n' "$1"; }
ok()   { printf '  (OK) %s\n' "$1"; }
warn() { printf '  (!!) %s\n' "$1"; }
die()  { printf '\n%s\n' "$1" >&2; exit 1; }

have() { command -v "$1" >/dev/null 2>&1; }

printf '\nCloudRadial AutomationAI - runner prerequisite installer (macOS)\n'
printf -- '---------------------------------------------------------------\n'

if [ "$(uname -s)" != "Darwin" ]; then
  die "This script is for macOS. On Linux use install-runner-prereqs-linux.sh; on Windows use Install-RunnerPrereqs.ps1."
fi

MACOS_VERSION="$(sw_vers -productVersion 2>/dev/null || echo 'unknown')"
printf 'macOS %s on %s.\n' "$MACOS_VERSION" "$(uname -m)"

MACOS_MAJOR="${MACOS_VERSION%%.*}"
case "$MACOS_MAJOR" in
  ''|*[!0-9]*) : ;;
  *) if [ "$MACOS_MAJOR" -lt 13 ]; then
       warn "The Azure CLI Homebrew formula requires macOS 13 or later. This machine reports $MACOS_VERSION."
     fi ;;
esac

# ----- Homebrew ---------------------------------------------------------------
step "Checking Homebrew"

if have brew; then
  ok "Homebrew is installed."
else
  warn "Homebrew is not installed. It is how PowerShell and the Azure CLI are installed on macOS."
  DO_BREW=0
  if [ "$ASSUME_YES" -eq 1 ]; then
    DO_BREW=1
  else
    printf '  Install Homebrew now? [y/N] '
    read -r reply </dev/tty || reply=""
    case "$reply" in [yY]*) DO_BREW=1 ;; esac
  fi

  if [ "$DO_BREW" -ne 1 ]; then
    die "Homebrew is required. Install it from https://brew.sh and re-run this script."
  fi

  printf '  Installing Homebrew (this uses the official installer and will prompt for your password)...\n'
  /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

  # A fresh install is not on the PATH of this already-running shell.
  for brew_candidate in /opt/homebrew/bin/brew /usr/local/bin/brew; do
    if [ -x "$brew_candidate" ]; then
      eval "$("$brew_candidate" shellenv)"
      break
    fi
  done

  have brew || die "Homebrew installed but 'brew' is still not on the PATH. Open a new terminal and re-run this script."
  ok "Homebrew is installed."
fi

# ----- PowerShell 7 -----------------------------------------------------------
# 'powershell' is a Homebrew CORE FORMULA (it used to be a cask). Do not use
# --cask here; that name no longer exists.
step "PowerShell 7"

if have pwsh && [ "$FORCE" -eq 0 ]; then
  ok "PowerShell 7 (pwsh) is already installed."
else
  printf '  Installing PowerShell via Homebrew...\n'
  brew update
  if have pwsh; then
    brew upgrade powershell || warn "brew upgrade powershell reported an issue; continuing."
  else
    brew install powershell
  fi
  if have pwsh; then ok "PowerShell 7 installed."; else warn "pwsh is still not on the PATH."; fi
fi

# ----- Azure CLI --------------------------------------------------------------
step "Azure CLI"

if have az && [ "$FORCE" -eq 0 ]; then
  ok "Azure CLI (az) is already installed."
else
  printf '  Installing the Azure CLI via Homebrew...\n'
  brew update
  if have az; then
    brew upgrade azure-cli || warn "brew upgrade azure-cli reported an issue; continuing."
  else
    brew install azure-cli
  fi
  if have az; then ok "Azure CLI installed."; else warn "az is still not on the PATH."; fi
fi

# ----- Bicep CLI --------------------------------------------------------------
# The runner deploys through Az PowerShell (New-AzResourceGroupDeployment
# -TemplateFile main.bicep), and Az PowerShell only ever looks for a standalone
# 'bicep' on the PATH. The Azure CLI's private copy (az bicep) does NOT satisfy
# it. We install Microsoft's published binary rather than the azure/bicep
# Homebrew tap, because current Homebrew refuses to load untrusted third-party
# taps without a separate 'brew trust' step.
step "Bicep CLI"

if have bicep && [ "$FORCE" -eq 0 ]; then
  ok "Bicep CLI (bicep) is already installed at $(command -v bicep)."
else
  case "$(uname -m)" in
    arm64)  BICEP_ASSET="bicep-osx-arm64" ;;
    x86_64) BICEP_ASSET="bicep-osx-x64" ;;
    *)      die "Unsupported architecture $(uname -m) for the Bicep CLI. Install it manually: https://aka.ms/bicep-install" ;;
  esac

  BICEP_TMP="$(mktemp -t bicep)"
  trap 'rm -f "$BICEP_TMP"' EXIT

  printf '  Downloading %s from the official Bicep release...\n' "$BICEP_ASSET"
  curl -fsSL -o "$BICEP_TMP" "https://github.com/Azure/bicep/releases/latest/download/$BICEP_ASSET"
  chmod +x "$BICEP_TMP"

  printf '  Installing to %s (requires sudo)...\n' "$BICEP_INSTALL_PATH"
  sudo mkdir -p "$(dirname "$BICEP_INSTALL_PATH")"
  sudo cp "$BICEP_TMP" "$BICEP_INSTALL_PATH"
  sudo chmod +x "$BICEP_INSTALL_PATH"
  # Clear the quarantine flag Gatekeeper sets on downloaded binaries.
  sudo xattr -d com.apple.quarantine "$BICEP_INSTALL_PATH" 2>/dev/null || true

  rm -f "$BICEP_TMP"
  trap - EXIT

  hash -r 2>/dev/null || true
  if have bicep; then ok "Bicep CLI installed."; else warn "bicep is still not on the PATH ($BICEP_INSTALL_PATH may not be in PATH)."; fi
fi

# ----- Az PowerShell modules --------------------------------------------------
step "Az PowerShell modules"

if [ "$SKIP_AZ_MODULES" -eq 1 ]; then
  warn "Skipped (--skip-az-modules). The runner installer will install them on first run."
elif ! have pwsh; then
  warn "pwsh is not available, so the Az modules cannot be installed."
  printf '       Open a new terminal, run pwsh, then: Install-Module Az -Scope CurrentUser\n'
else
  printf '  Installing the Az submodules the runner scripts use (CurrentUser scope).\n'
  printf '  This is a one-time install and can take several minutes.\n'
  # $true/$false are PowerShell literals for the pwsh command below, not bash vars.
  # shellcheck disable=SC2016
  if [ "$FORCE" -eq 1 ]; then FORCE_PS='$true'; else FORCE_PS='$false'; fi
  if pwsh -NoProfile -NonInteractive -Command "
\$ErrorActionPreference = 'Stop'
\$required = @($AZ_MODULES)
\$forceInstall = $FORCE_PS
foreach (\$m in \$required) {
    if (-not \$forceInstall -and (Get-Module -ListAvailable -Name \$m)) {
        Write-Host \"  (OK) \$m already installed.\"
        continue
    }
    Write-Host \"  Installing \$m ...\"
    Install-Module -Name \$m -Scope CurrentUser -Repository PSGallery -Force -AllowClobber -Confirm:\$false -ErrorAction Stop
    Write-Host \"  (OK) \$m installed.\"
}
"; then
    ok "Az PowerShell modules are installed."
  else
    # Never let a PSGallery hiccup abort the run under `set -e`: the operator
    # would lose the verification table AND the remediation text that follows.
    # The runner installer retries the Az submodules on its first run anyway.
    warn "Az module install did not complete. The verification below shows what is still missing."
  fi
fi

# ----- Verification -----------------------------------------------------------
step "Verification"

MISSING=0

if have pwsh; then
  # $PSVersionTable is a PowerShell variable evaluated by pwsh, not by bash.
  # shellcheck disable=SC2016
  printf '  PowerShell 7 (pwsh)   : %s\n' "$(pwsh -NoProfile -Command '$PSVersionTable.PSVersion.ToString()' 2>/dev/null || echo 'installed')"
else
  printf '  PowerShell 7 (pwsh)   : MISSING\n'; MISSING=1
fi

if have az; then
  printf '  Azure CLI (az)        : %s\n' "$(az version --output tsv --query '"azure-cli"' 2>/dev/null || echo 'installed')"
else
  printf '  Azure CLI (az)        : MISSING\n'; MISSING=1
fi

if have bicep; then
  printf '  Bicep CLI (bicep)     : %s\n' "$(bicep --version 2>/dev/null | head -1 || echo 'installed')"
else
  printf '  Bicep CLI (bicep)     : MISSING\n'; MISSING=1
fi

if [ "$SKIP_AZ_MODULES" -eq 0 ]; then
  if have pwsh; then
    AZ_MISSING="$(pwsh -NoProfile -NonInteractive -Command "@($AZ_MODULES) | Where-Object { -not (Get-Module -ListAvailable -Name \$_) } | ForEach-Object { \$_ }" 2>/dev/null | tr -d '\r' | tr '\n' ' ' | sed 's/ *$//')"
    if [ -z "$AZ_MISSING" ]; then
      printf '  Az PowerShell modules : all present\n'
    else
      printf '  Az PowerShell modules : MISSING: %s\n' "$AZ_MISSING"; MISSING=1
    fi
  else
    printf '  Az PowerShell modules : MISSING (no pwsh)\n'; MISSING=1
  fi
fi

printf '\n'

if [ "$MISSING" -ne 0 ]; then
  printf 'Some prerequisites are still missing.\n\n'
  printf 'What to do next:\n'
  printf '  1. Open a NEW terminal window. A newly installed tool is not on the PATH of a\n'
  printf '     shell that was already open.\n'
  printf '  2. Re-run this script. It is safe to run repeatedly.\n'
  printf '  3. If a tool still will not install, follow the manual steps in\n'
  printf '     "Runner prerequisites and Azure requirements" on the CloudRadial support site.\n\n'
  exit 1
fi

printf 'All local prerequisites are installed.\n\n'
printf 'Next steps:\n'
printf '  1. Start PowerShell 7:                pwsh\n'
printf '  2. Sign in to Azure (Az PowerShell):  Connect-AzAccount\n'
printf '  3. Extract your runner setup package and run:  ./Install-AutomationsRunner.ps1\n\n'
printf 'Connect-AzAccount is a separate sign-in from "az login" - the runner installer\n'
printf 'uses the Az PowerShell one.\n\n'
