#!/usr/bin/env bash
# Create emergency Git bundle backups from Gitea over Git HTTP.
# This is a repository-history fallback only. It does not replace `gitea dump`,
# does not back up Gitea DB rows, settings, issues, packages, secrets, or LFS.

set -euo pipefail

GITEA_BASE_URL="${GITEA_BASE_URL:-http://192.168.0.110:3001}"
OUTPUT_ROOT="${OUTPUT_ROOT:-/home/ollama/backup/110/gitea/git-bundles}"
TIMEOUT_LS_REMOTE_SECONDS="${TIMEOUT_LS_REMOTE_SECONDS:-60}"
TIMEOUT_CLONE_SECONDS="${TIMEOUT_CLONE_SECONDS:-180}"
TIMEOUT_BUNDLE_SECONDS="${TIMEOUT_BUNDLE_SECONDS:-180}"
TIMEOUT_VERIFY_SECONDS="${TIMEOUT_VERIFY_SECONDS:-60}"
STAMP="${STAMP:-$(date +%Y%m%d-%H%M%S)}"
DRY_RUN=0
REPOS=()

usage() {
  cat <<'USAGE'
Usage: scripts/backup/gitea-repo-bundle-backup.sh [options]

Options:
  --repo OWNER/NAME   Repository to bundle. May be passed more than once.
  --output-root PATH  Bundle root. Default: /home/ollama/backup/110/gitea/git-bundles
  --gitea-base URL    Gitea base URL. Default: http://192.168.0.110:3001
  --stamp STAMP       Output directory stamp. Default: current local timestamp.
  --dry-run           Print target URLs without cloning or writing bundles.
  -h, --help          Show this help.

This script uses GIT_TERMINAL_PROMPT=0 and never asks for, reads, or prints
tokens or passwords. Private repositories without an existing credential fail
closed in the manifest.
USAGE
}

while [ "$#" -gt 0 ]; do
  case "$1" in
    --repo)
      shift
      REPOS+=("${1:?--repo requires OWNER/NAME}")
      ;;
    --output-root)
      shift
      OUTPUT_ROOT="${1:?--output-root requires PATH}"
      ;;
    --gitea-base)
      shift
      GITEA_BASE_URL="${1:?--gitea-base requires URL}"
      ;;
    --stamp)
      shift
      STAMP="${1:?--stamp requires value}"
      ;;
    --dry-run)
      DRY_RUN=1
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    *)
      echo "Unknown argument: $1" >&2
      usage >&2
      exit 64
      ;;
  esac
  shift
done

if [ "${#REPOS[@]}" -eq 0 ]; then
  REPOS=(
    "wooo/awoooi"
    "wooo/ewoooc"
    "wooo/2026FIFAWorldCup"
    "wooo/agent-bounty-protocol"
    "wooo/AwoooGo"
    "wooo/stockplatform-v2"
    "wooo/vibework"
    "wooo/momo-pro-system"
    "wooo/tsenyang-website"
    "wooo/clawbot-v5"
    "wooo/bitan-pharmacy"
    "wooo/vtuber"
  )
fi

if [ "$DRY_RUN" -eq 1 ]; then
  for repo in "${REPOS[@]}"; do
    printf 'DRY_RUN repo=%s url=%s/%s.git\n' "$repo" "$GITEA_BASE_URL" "$repo"
  done
  exit 0
fi

backup_root="${OUTPUT_ROOT%/}/${STAMP}"
tmp_root="$(mktemp -d "${TMPDIR:-/tmp}/gitea-bundle.XXXXXX")"
manifest="${backup_root}/manifest.tsv"
mkdir -p "$backup_root"
trap 'rm -rf "$tmp_root"' EXIT

printf 'repo\tstatus\thead_count\tbundle\tchecksum\n' > "$manifest"

for repo in "${REPOS[@]}"; do
  slug="${repo//\//__}"
  url="${GITEA_BASE_URL%/}/${repo}.git"
  refs_file="${backup_root}/${slug}.refs"
  err_file="${backup_root}/${slug}.err"
  bundle_file="${backup_root}/${slug}.bundle"
  checksum_file="${bundle_file}.sha256"
  repo_tmp="${tmp_root}/${slug}.git"

  if ! GIT_TERMINAL_PROMPT=0 timeout "$TIMEOUT_LS_REMOTE_SECONDS" \
    git ls-remote --heads "$url" >"$refs_file" 2>"$err_file"; then
    printf '%s\tls_remote_failed\t0\t\t\n' "$repo" >> "$manifest"
    continue
  fi

  head_count="$(wc -l < "$refs_file" | tr -d ' ')"
  rm -rf "$repo_tmp"
  if ! GIT_TERMINAL_PROMPT=0 timeout "$TIMEOUT_CLONE_SECONDS" \
    git clone --mirror --quiet "$url" "$repo_tmp" 2>>"$err_file"; then
    printf '%s\tclone_failed\t%s\t\t\n' "$repo" "$head_count" >> "$manifest"
    continue
  fi

  if ! timeout "$TIMEOUT_BUNDLE_SECONDS" \
    git -C "$repo_tmp" bundle create "$bundle_file" --all >/dev/null 2>>"$err_file"; then
    printf '%s\tbundle_failed\t%s\t\t\n' "$repo" "$head_count" >> "$manifest"
    continue
  fi

  if ! timeout "$TIMEOUT_VERIFY_SECONDS" \
    git -C "$repo_tmp" bundle verify "$bundle_file" >/dev/null 2>>"$err_file"; then
    printf '%s\tverify_failed\t%s\t%s\t\n' "$repo" "$head_count" "$bundle_file" >> "$manifest"
    continue
  fi

  (sha256sum "$bundle_file" 2>/dev/null || shasum -a 256 "$bundle_file") > "$checksum_file"
  rm -rf "$repo_tmp"
  printf '%s\tok\t%s\t%s\t%s\n' "$repo" "$head_count" "$bundle_file" "$checksum_file" >> "$manifest"
done

latest_link="${OUTPUT_ROOT%/}/latest"
if [ ! -e "$latest_link" ] || [ -L "$latest_link" ]; then
  ln -sfn "$backup_root" "$latest_link"
else
  echo "WARN latest path exists and is not a symlink: $latest_link" >&2
fi
cat "$manifest"
