#!/usr/bin/env bash

set -euo pipefail

usage() {
  cat <<'EOF'
Import a root CA from macOS keychain into all installed Java truststores.

Usage:
  import-macos-root-ca-into-java.sh --name "<certificate common name>" [--alias "<java alias>"] [--storepass "<password>"]
  import-macos-root-ca-into-java.sh --sha256 "<sha256 fingerprint>" [--alias "<java alias>"] [--storepass "<password>"]

Examples:
  import-macos-root-ca-into-java.sh --name "savignano Root CA G4" --alias sss_root_G4
  import-macos-root-ca-into-java.sh --sha256 "99:CC:3C:A2:FD:EA:9B:58:F3:9F:C3:18:39:23:B0:A2:E1:50:31:84:94:89:8B:14:13:1F:28:CF:E2:27:C2:B0" --alias sss_root_G4

Notes:
  - Requires macOS `security`, `openssl`, and `keytool`.
  - Uses sudo for modifying Java cacerts files.
  - Default keystore password is "changeit".
EOF
}

CERT_NAME=""
CERT_SHA256=""
CERT_ALIAS=""
STOREPASS="${STOREPASS:-changeit}"
KEYCHAIN="${KEYCHAIN:-/Library/Keychains/System.keychain}"

while [[ $# -gt 0 ]]; do
  case "$1" in
    -n|--name)
      CERT_NAME="${2:-}"
      shift 2
      ;;
    -s|--sha256)
      CERT_SHA256="${2:-}"
      shift 2
      ;;
    -a|--alias)
      CERT_ALIAS="${2:-}"
      shift 2
      ;;
    --storepass)
      STOREPASS="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage
      exit 2
      ;;
  esac
done

if [[ -z "$CERT_NAME" && -z "$CERT_SHA256" ]]; then
  echo "Provide either --name or --sha256." >&2
  usage
  exit 2
fi

for cmd in security openssl keytool; do
  if ! command -v "$cmd" >/dev/null 2>&1; then
    echo "Missing required command: $cmd" >&2
    exit 1
  fi
done

normalize_fp() {
  tr -d '[:space:]:.-' | tr '[:lower:]' '[:upper:]'
}

make_alias() {
  printf '%s' "$1" \
    | tr '[:upper:]' '[:lower:]' \
    | sed -E 's/[^a-z0-9._-]+/_/g; s/^_+//; s/_+$//; s/_{2,}/_/g'
}

TARGET_FP=""
if [[ -n "$CERT_SHA256" ]]; then
  TARGET_FP="$(printf '%s' "$CERT_SHA256" | normalize_fp)"
fi

WORKDIR="$(mktemp -d /tmp/macos-ca-import.XXXXXX)"
trap 'rm -rf "$WORKDIR"' EXIT

ALL_PEMS="$WORKDIR/all.pem"
SELECTED_CERT="$WORKDIR/selected.pem"

if [[ -n "$CERT_NAME" ]]; then
  security find-certificate -a -p -c "$CERT_NAME" "$KEYCHAIN" > "$ALL_PEMS" || true
  if [[ ! -s "$ALL_PEMS" ]]; then
    echo "No certificate found by name in $KEYCHAIN: $CERT_NAME" >&2
    exit 1
  fi
else
  security find-certificate -a -p "$KEYCHAIN" > "$ALL_PEMS"
fi

# Split PEM bundle into files cert_0001.pem, cert_0002.pem, ...
awk '
/-----BEGIN CERTIFICATE-----/ {in_cert=1; n++; fn=sprintf("'"$WORKDIR"'/cert_%04d.pem", n)}
in_cert {print > fn}
/-----END CERTIFICATE-----/ {in_cert=0}
' "$ALL_PEMS"

CERT_FILES=()
while IFS= read -r line; do
  CERT_FILES+=("$line")
done < <(ls "$WORKDIR"/cert_*.pem 2>/dev/null || true)
if [[ ${#CERT_FILES[@]} -eq 0 ]]; then
  echo "No parseable certificate blocks found." >&2
  exit 1
fi

MATCHES=0
for cert_file in "${CERT_FILES[@]}"; do
  CERT_FP="$(openssl x509 -in "$cert_file" -noout -fingerprint -sha256 | awk -F= '{print $2}' | normalize_fp)"

  if [[ -n "$TARGET_FP" && "$CERT_FP" != "$TARGET_FP" ]]; then
    continue
  fi

  cp "$cert_file" "$SELECTED_CERT"
  MATCHES=$((MATCHES + 1))
done

if [[ $MATCHES -eq 0 ]]; then
  if [[ -n "$TARGET_FP" ]]; then
    echo "No matching certificate found for fingerprint: $CERT_SHA256" >&2
  else
    echo "No matching certificate found." >&2
  fi
  exit 1
fi

if [[ $MATCHES -gt 1 ]]; then
  echo "Warning: multiple matching certificates found; using the last match." >&2
fi

if [[ -z "$CERT_ALIAS" ]]; then
  if [[ -n "$CERT_NAME" ]]; then
    CERT_ALIAS="$(make_alias "$CERT_NAME")"
  else
    SUBJECT="$(openssl x509 -in "$SELECTED_CERT" -noout -subject -nameopt RFC2253)"
    CN="$(printf '%s' "$SUBJECT" | sed -E 's/.*CN=([^,]+).*/\1/')"
    CERT_ALIAS="$(make_alias "$CN")"
  fi
fi

if [[ -z "$CERT_ALIAS" ]]; then
  CERT_ALIAS="imported_root_ca"
fi

CERT_SUMMARY="$(openssl x509 -in "$SELECTED_CERT" -noout -subject -issuer -fingerprint -sha256)"
echo "Selected certificate:"
echo "$CERT_SUMMARY"
echo "Java alias: $CERT_ALIAS"
echo

JDK_HOMES=()
while IFS= read -r line; do
  JDK_HOMES+=("$line")
done < <(/usr/libexec/java_home -V 2>&1 | sed -nE 's#.* (/.*Contents/Home)$#\1#p' | sort -u)
if [[ ${#JDK_HOMES[@]} -eq 0 ]]; then
  echo "No JDKs detected by /usr/libexec/java_home -V." >&2
  exit 1
fi

IMPORTED=0
for jh in "${JDK_HOMES[@]}"; do
  KS1="$jh/lib/security/cacerts"
  KS2="$jh/jre/lib/security/cacerts"
  KEYSTORE=""

  if [[ -f "$KS1" ]]; then
    KEYSTORE="$KS1"
  elif [[ -f "$KS2" ]]; then
    KEYSTORE="$KS2"
  else
    echo "Skip (no cacerts): $jh"
    continue
  fi

  echo "==> Importing into: $KEYSTORE"
  sudo keytool -delete -alias "$CERT_ALIAS" -keystore "$KEYSTORE" -storepass "$STOREPASS" >/dev/null 2>&1 || true
  sudo keytool -importcert -noprompt -trustcacerts -alias "$CERT_ALIAS" -file "$SELECTED_CERT" -keystore "$KEYSTORE" -storepass "$STOREPASS"
  IMPORTED=$((IMPORTED + 1))
done

echo
echo "Imported into $IMPORTED Java truststore(s)."
