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

# =============================================================================
# Defaults (override via CLI flags)
# =============================================================================
REGISTRY="https://git.motovaultpro.com"
USERNAME="egullickson"
TOKEN=""
KEEP_TAG="latest"
DRY_RUN=0

REPOS=(
  "egullickson/frontend"
  "egullickson/backend"
)
# =============================================================================

need() { command -v "$1" >/dev/null || { echo "ERROR: missing dependency: $1"; exit 1; }; }
need curl
need jq

usage() {
  cat <<EOF
Usage:
  $0 --token=YOUR_PAT [--user=egullickson] [--registry=https://git.motovaultpro.com]
     [--keep-tag=latest] [--dry-run|--no-dry-run]

Examples:
  # Preview
  $0 --token=XXXX --dry-run

  # Actually delete
  $0 --token=XXXX --no-dry-run

Notes:
  - Deletes all tags except KEEP_TAG for repos:
      ${REPOS[*]}
  - Protects KEEP_TAG by digest (won't delete anything pointing to KEEP_TAG digest).
EOF
}

# --- CLI parsing -------------------------------------------------------------
for arg in "$@"; do
  case "$arg" in
    --token=*) TOKEN="${arg#*=}" ;;
    --user=*) USERNAME="${arg#*=}" ;;
    --registry=*) REGISTRY="${arg#*=}" ;;
    --keep-tag=*) KEEP_TAG="${arg#*=}" ;;
    --dry-run) DRY_RUN=1 ;;
    --no-dry-run) DRY_RUN=0 ;;
    -h|--help) usage; exit 0 ;;
    *)
      echo "ERROR: Unknown argument: $arg"
      usage
      exit 1
      ;;
  esac
done

if [[ -z "$TOKEN" ]]; then
  echo "ERROR: --token= is required"
  usage
  exit 1
fi

ACCEPT_MANIFEST="application/vnd.oci.image.manifest.v1+json, application/vnd.oci.image.index.v1+json, application/vnd.docker.distribution.manifest.v2+json"

get_bearer_token() {
  local repo="$1"
  local scope="repository:${repo}:pull,delete"
  curl -fsS -u "${USERNAME}:${TOKEN}" \
    "${REGISTRY}/v2/token?service=container_registry&scope=${scope}" \
  | jq -r '.token // .access_token // empty'
}

auth_header_for_repo() {
  local repo="$1"
  local t
  t="$(get_bearer_token "$repo")"
  if [[ -z "$t" ]]; then
    echo "ERROR: Could not obtain bearer token for ${repo} (check PAT permissions)."
    exit 1
  fi
  echo "Authorization: Bearer ${t}"
}

tags_list() {
  local repo="$1" auth="$2"
  curl -fsS -H "$auth" "${REGISTRY}/v2/${repo}/tags/list"
}

digest_for_tag() {
  local repo="$1" tag="$2" auth="$3"
  curl -fsSI \
    -H "$auth" \
    -H "Accept: ${ACCEPT_MANIFEST}" \
    "${REGISTRY}/v2/${repo}/manifests/${tag}" \
  | tr -d '\r' \
  | awk 'BEGIN{IGNORECASE=1} /^docker-content-digest:/ {print $2; exit}'
}

delete_digest() {
  local repo="$1" digest="$2" auth="$3"
  if [[ "$DRY_RUN" == "1" ]]; then
    echo "DRY_RUN: DELETE ${REGISTRY}/v2/${repo}/manifests/${digest}"
    return 0
  fi

  curl -fsS -X DELETE -H "$auth" \
    "${REGISTRY}/v2/${repo}/manifests/${digest}" >/dev/null
}

purge_repo_keep_tag() {
  local repo="$1"
  echo "== Purging ${repo} (keep ${KEEP_TAG}) =="

  local auth
  auth="$(auth_header_for_repo "$repo")"

  local json tags
  json="$(tags_list "$repo" "$auth")"
  tags="$(echo "$json" | jq -r '.tags[]?' | sort || true)"

  if [[ -z "$tags" ]]; then
    echo "No tags found."
    echo
    return 0
  fi

  if ! echo "$tags" | grep -qx "${KEEP_TAG}"; then
    echo "WARN: No '${KEEP_TAG}' tag found; refusing to purge ${repo}."
    echo "$tags" | sed 's/^/  - /'
    echo
    return 0
  fi

  local keep_digest
  keep_digest="$(digest_for_tag "$repo" "$KEEP_TAG" "$auth" || true)"
  if [[ -z "$keep_digest" ]]; then
    echo "ERROR: Could not resolve digest for ${repo}:${KEEP_TAG}"
    echo "Tip: curl -vI -H \"$auth\" ${REGISTRY}/v2/${repo}/manifests/${KEEP_TAG}"
    echo
    return 1
  fi
  echo "${KEEP_TAG} digest: ${keep_digest}"

  # Collect digests referenced by non-KEEP_TAG tags (skipping those equal to keep_digest)
  local digests=()
  while read -r tag; do
    [[ -z "$tag" || "$tag" == "$KEEP_TAG" ]] && continue

    local d
    d="$(digest_for_tag "$repo" "$tag" "$auth" || true)"
    if [[ -z "$d" ]]; then
      echo "WARN: couldn't resolve digest for tag=${tag} (skipping)"
      continue
    fi

    if [[ "$d" == "$keep_digest" ]]; then
      echo "SKIP: tag=${tag} points to ${KEEP_TAG} digest (deleting would remove ${KEEP_TAG} too)"
      continue
    fi

    digests+=("$d")
  done <<< "$tags"

  if [[ "${#digests[@]}" -eq 0 ]]; then
    echo "Nothing to delete."
    echo
    return 0
  fi

  echo "Will delete (deduped) manifest(s) (and all tags pointing to them)."
  printf '%s\n' "${digests[@]}" | sort -u | while read -r digest; do
    [[ -z "$digest" ]] && continue
    echo "Deleting digest: $digest"
    if ! delete_digest "$repo" "$digest" "$auth"; then
      echo "WARN: delete failed for $digest"
    fi
  done

  echo "Done."
  echo
}

for repo in "${REPOS[@]}"; do
  purge_repo_keep_tag "$repo"
done

echo "Complete."
