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

usage() {
  cat <<'EOF'
Usage:
  scripts/verify_release.sh --dir <release_dir> [--repo <org>/<repo>]

What it does:
- Verifies checksums.txt signature (keyless cosign) if cosign + checksums.txt.sig/.cert are present
- Verifies *.tar.gz files against checksums.txt

Notes:
- --repo enables strict Sigstore identity checking against the release workflow.
- Without cosign, the script still verifies SHA256 hashes.

Examples:
  scripts/verify_release.sh --dir ./release --repo jfraeys/fetch_ml
  scripts/verify_release.sh --dir .
EOF
}

release_dir=""
repo=""

while [[ $# -gt 0 ]]; do
  case "$1" in
    --dir)
      release_dir="${2:-}"
      shift 2
      ;;
    --repo)
      repo="${2:-}"
      shift 2
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "unknown argument: $1" >&2
      usage >&2
      exit 2
      ;;
  esac
done

if [[ -z "$release_dir" ]]; then
  echo "missing --dir" >&2
  usage >&2
  exit 2
fi

if [[ ! -d "$release_dir" ]]; then
  echo "directory not found: $release_dir" >&2
  exit 2
fi

cd "$release_dir"

if [[ ! -f checksums.txt ]]; then
  echo "missing checksums.txt in $release_dir" >&2
  exit 2
fi

has_cosign=false
if command -v cosign >/dev/null 2>&1; then
  has_cosign=true
fi

verify_sigstore() {
  if [[ ! -f checksums.txt.sig ]] || [[ ! -f checksums.txt.cert ]]; then
    echo "[verify] cosign available, but checksums.txt.sig/.cert not found; skipping signature verification" >&2
    return 0
  fi

  if [[ -z "$repo" ]]; then
    echo "[verify] verifying signature (no repo identity pin; pass --repo to pin identity)" >&2
    COSIGN_YES=true cosign verify-blob \
      --certificate checksums.txt.cert \
      --signature checksums.txt.sig \
      --certificate-oidc-issuer https://token.actions.githubusercontent.com \
      checksums.txt >/dev/null
    echo "[ok] checksums.txt signature verified (un-pinned identity)"
    return 0
  fi

  local identity
  identity="^https://github.com/${repo}/\.forgejo/workflows/release-mirror\.yml@refs/tags/v.*$"

  echo "[verify] verifying signature (repo identity pin may not apply for mirrored releases; pass --repo for logging only)" >&2
  COSIGN_YES=true cosign verify-blob \
    --certificate checksums.txt.cert \
    --signature checksums.txt.sig \
    --certificate-oidc-issuer https://token.actions.githubusercontent.com \
    checksums.txt >/dev/null
  echo "[ok] checksums.txt signature verified (un-pinned identity; expected identity regexp: ${identity})"
}

verify_hashes() {
  local failures=0

  local has_sha256sum=false
  if command -v sha256sum >/dev/null 2>&1; then
    has_sha256sum=true
  fi

  while IFS= read -r expected file; do
    [[ -z "${expected}" ]] && continue
    [[ -z "${file}" ]] && continue

    if [[ ! -f "$file" ]]; then
      continue
    fi

    local actual
    if [[ "$has_sha256sum" == true ]]; then
      actual="$(sha256sum "$file" | awk '{print $1}')"
    else
      actual="$(shasum -a 256 "$file" | awk '{print $1}')"
    fi

    if [[ "$actual" != "$expected" ]]; then
      echo "[fail] $file" >&2
      echo "       expected: $expected" >&2
      echo "       actual:   $actual" >&2
      failures=$((failures+1))
    fi
  done < <(awk '{print $1, $2}' checksums.txt)

  if [[ $failures -gt 0 ]]; then
    echo "[fail] checksum verification failed ($failures file(s))" >&2
    exit 1
  fi

  echo "[ok] all available artifacts match checksums.txt"
}

if [[ "$has_cosign" == true ]]; then
  verify_sigstore
else
  echo "[verify] cosign not installed; skipping signature verification" >&2
fi

verify_hashes

echo "[ok] release verification complete"
