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

# ==========================================
# Root CA bootstrap + install script
# For Linux/macOS/WSL/Git Bash
# ==========================================

# Defaults can be overridden with env vars or CLI args
CA_URL="${CA_URL:-https://ca.insmw.internal}"
CA_FINGERPRINT="${CA_FINGERPRINT:-}"
STEP_VERSION="${STEP_VERSION:-0.28.7}"
STEP_BIN_DIR="${STEP_BIN_DIR:-/usr/local/bin}"
STEP_CONFIG_DIR="${STEP_CONFIG_DIR:-$HOME/.step}"
FORCE="${FORCE:-0}"

usage() {
  cat <<EOF
Usage:
  $0 --ca-url <url> --fingerprint <fingerprint> [--force]

Examples:
  curl -fsSL https://your-opengist/raw/install-ca.sh | bash -s -- \\
    --ca-url https://ca.insmw.internal \\
    --fingerprint abcdef1234567890...

Environment variables:
  CA_URL
  CA_FINGERPRINT
  STEP_VERSION
  STEP_BIN_DIR
  STEP_CONFIG_DIR
  FORCE=1

EOF
}

log() {
  printf '\n[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
}

fail() {
  echo "ERROR: $*" >&2
  exit 1
}

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

download_file() {
  local url="$1"
  local out="$2"

  if need_cmd curl; then
    curl -fsSL "$url" -o "$out"
  elif need_cmd wget; then
    wget -qO "$out" "$url"
  else
    fail "Neither curl nor wget is installed"
  fi
}

detect_os() {
  local uname_s
  uname_s="$(uname -s 2>/dev/null || true)"

  case "$uname_s" in
    Linux*) echo "linux" ;;
    Darwin*) echo "darwin" ;;
    MINGW*|MSYS*|CYGWIN*) echo "windows_bash" ;;
    *) echo "unknown" ;;
  esac
}

detect_arch() {
  local uname_m
  uname_m="$(uname -m 2>/dev/null || true)"

  case "$uname_m" in
    x86_64|amd64) echo "amd64" ;;
    aarch64|arm64) echo "arm64" ;;
    armv7l) echo "armv7" ;;
    *) echo "$uname_m" ;;
  esac
}

install_step_linux() {
  local arch="$1"
  local tmpdir pkg_ext pkg_name url

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

  if need_cmd apk; then
    pkg_ext="apk"
    case "$arch" in
      amd64) pkg_name="step-cli_${STEP_VERSION}_amd64.apk" ;;
      arm64) pkg_name="step-cli_${STEP_VERSION}_arm64.apk" ;;
      *) fail "Unsupported architecture for Alpine: $arch" ;;
    esac

    url="https://github.com/smallstep/cli/releases/download/v${STEP_VERSION}/${pkg_name}"
    log "Downloading step-cli from $url"
    download_file "$url" "$tmpdir/$pkg_name"
    sudo apk add --allow-untrusted "$tmpdir/$pkg_name"
    return
  fi

  if need_cmd dpkg; then
    pkg_ext="deb"
    case "$arch" in
      amd64) pkg_name="step-cli_${STEP_VERSION}_amd64.deb" ;;
      arm64) pkg_name="step-cli_${STEP_VERSION}_arm64.deb" ;;
      *) fail "Unsupported architecture for Debian/Ubuntu: $arch" ;;
    esac

    url="https://github.com/smallstep/cli/releases/download/v${STEP_VERSION}/${pkg_name}"
    log "Downloading step-cli from $url"
    download_file "$url" "$tmpdir/$pkg_name"
    sudo dpkg -i "$tmpdir/$pkg_name" || sudo apt-get update && sudo apt-get install -f -y
    return
  fi

  fail "Unsupported Linux distribution. Supported: Debian/Ubuntu, Alpine"
}

install_step_darwin() {
  if need_cmd brew; then
    log "Installing step via Homebrew"
    brew install step
    return
  fi

  fail "Homebrew is required on macOS to install step automatically"
}

ensure_step() {
  local os arch
  if need_cmd step; then
    log "step CLI already installed"
    return
  fi

  os="$(detect_os)"
  arch="$(detect_arch)"

  log "step CLI not found, installing for $os/$arch"

  case "$os" in
    linux) install_step_linux "$arch" ;;
    darwin) install_step_darwin ;;
    windows_bash)
      fail "For native Windows, use the PowerShell installer instead of the bash script"
      ;;
    *)
      fail "Unsupported OS: $os"
      ;;
  esac

  need_cmd step || fail "step CLI installation failed"
}

bootstrap_step() {
  [ -n "$CA_FINGERPRINT" ] || fail "CA fingerprint is required"

  if [ "$FORCE" = "1" ]; then
    log "Removing previous step configuration because FORCE=1"
    rm -rf "$STEP_CONFIG_DIR"
  fi

  mkdir -p "$STEP_CONFIG_DIR"

  log "Bootstrapping step against $CA_URL"
  step ca bootstrap \
    --ca-url "$CA_URL" \
    --fingerprint "$CA_FINGERPRINT" \
    --install \
    --force
}

install_linux_trust() {
  local root_cert
  root_cert="$STEP_CONFIG_DIR/certs/root_ca.crt"

  [ -f "$root_cert" ] || fail "Root certificate not found at $root_cert"

  if need_cmd update-ca-certificates; then
    log "Installing root CA into system trust store using update-ca-certificates"
    sudo mkdir -p /usr/local/share/ca-certificates
    sudo cp "$root_cert" /usr/local/share/ca-certificates/insmw-root-ca.crt
    sudo update-ca-certificates
    return
  fi

  if need_cmd trust; then
    log "Installing root CA into system trust store using p11-kit trust"
    sudo trust anchor "$root_cert"
    return
  fi

  if [ -d /etc/ssl/certs ]; then
    log "Copying certificate to /etc/ssl/certs as fallback"
    sudo cp "$root_cert" /etc/ssl/certs/insmw-root-ca.crt
    return
  fi

  fail "Could not determine how to install the CA into the Linux trust store"
}

install_macos_trust() {
  local root_cert
  root_cert="$STEP_CONFIG_DIR/certs/root_ca.crt"

  [ -f "$root_cert" ] || fail "Root certificate not found at $root_cert"

  log "Installing root CA into macOS System keychain"
  sudo security add-trusted-cert \
    -d \
    -r trustRoot \
    -k /Library/Keychains/System.keychain \
    "$root_cert"
}

install_trust_store() {
  local os
  os="$(detect_os)"

  case "$os" in
    linux) install_linux_trust ;;
    darwin) install_macos_trust ;;
    *)
      fail "Unsupported OS for trust installation: $os"
      ;;
  esac
}

verify_install() {
  local root_cert
  root_cert="$STEP_CONFIG_DIR/certs/root_ca.crt"

  log "Installed root CA at: $root_cert"
  log "Certificate subject:"
  step certificate inspect "$root_cert" --short || true

  echo
  echo "Done."
  echo "You may need to restart applications that cache trust settings, such as browsers or Docker."
}

parse_args() {
  while [ $# -gt 0 ]; do
    case "$1" in
      --ca-url)
        CA_URL="$2"
        shift 2
        ;;
      --fingerprint)
        CA_FINGERPRINT="$2"
        shift 2
        ;;
      --force)
        FORCE=1
        shift
        ;;
      -h|--help)
        usage
        exit 0
        ;;
      *)
        fail "Unknown argument: $1"
        ;;
    esac
  done
}

main() {
  parse_args "$@"

  [ -n "$CA_URL" ] || fail "CA URL is required"
  [ -n "$CA_FINGERPRINT" ] || fail "CA fingerprint is required"

  ensure_step
  bootstrap_step
  install_trust_store
  verify_install
}

main "$@"