#!/bin/ash
#
# Mirror android_cast git submodules into Gitea as pull mirrors, then print a
# .gitmodules snippet pointing at Gitea URLs (commit that on canonical git).
#
# Usage (on Alpine BE as root or GITEA RUN_USER):
#   sudo ./gitea_mirror_submodules.sh
#   sudo ./gitea_mirror_submodules.sh /path/to/android_cast/.gitmodules
#   GITEA_SUBMODULES_CONF=./extra.list sudo ./gitea_mirror_submodules.sh
#
# Requires [migrations] allowlist in app.ini for upstream hosts, e.g.:
#   ALLOW_LOCALNETWORKS = true
#   ALLOWED_DOMAINS = *,github.com,*.github.com,chromium.googlesource.com,git.zx2c4.com
#
set -eu

SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
# shellcheck source=gitea_ini.sh
. "$SCRIPT_DIR/gitea_ini.sh"
# shellcheck source=gitea_mirror_lib.sh
. "$SCRIPT_DIR/gitea_mirror_lib.sh"
# shellcheck source=gitea_org_lib.sh
. "$SCRIPT_DIR/gitea_org_lib.sh"

GITEA_OWNER="${GITEA_OWNER:-${GITEA_ORG:-AndroidCast}}"
GITEA_MIRROR_INTERVAL="${GITEA_MIRROR_INTERVAL:-24h}"
GITEA_PRIVATE="${GITEA_PRIVATE:-false}"
GITEA_SUBMODULES_CONF="${GITEA_SUBMODULES_CONF:-$SCRIPT_DIR/submodules.defaults.conf}"
WORK_DIR="${WORK_DIR:-}"
SNIPPET_OUT="${SNIPPET_OUT:-$WORK_DIR/gitmodules.gitea-snippet.ini}"

log() { printf '[gitea-submodules] %s\n' "$*"; }
warn() { printf '[gitea-submodules] WARN: %s\n' "$*" >&2; }
die() { printf '[gitea-submodules] ERROR: %s\n' "$*" >&2; exit 1; }

# Parse .gitmodules -> repo|url|path|branch lines (repo = basename of path).
parse_gitmodules_file() {
  _file="$1"
  [ -r "$_file" ] || return 1
  awk '
    function trim(s) {
      sub(/^[ \t]+/, "", s); sub(/[ \t]+$/, "", s)
      return s
    }
    /^[ \t]*path[ \t]*=/ {
      p = $0; sub(/^[^=]*=/, "", p); path = trim(p)
      n = path; sub(".*/", "", n)
      next
    }
    /^[ \t]*url[ \t]*=/ {
      u = $0; sub(/^[^=]*=/, "", u); url = trim(u)
      next
    }
    /^[ \t]*branch[ \t]*=/ {
      b = $0; sub(/^[^=]*=/, "", b); branch = trim(b)
      next
    }
    /^\[/ {
      if (path != "" && url != "" && n != "") {
        if (branch != "") print n "|" url "|" path "|" branch
        else print n "|" url "|" path
      }
      path = ""; url = ""; branch = ""; n = ""
    }
    END {
      if (path != "" && url != "" && n != "") {
        if (branch != "") print n "|" url "|" path "|" branch
        else print n "|" url "|" path
      }
    }
  ' "$_file"
}

# repo|upstream|path[|branch] — stdout only; status lines go to stderr.
is_valid_submodule_entry() {
  case "$1" in
    *'|'*) ;;
    *) return 1 ;;
  esac
  _repo="${1%%|*}"
  _rest="${1#*|}"
  _url="${_rest%%|*}"
  _rest2="${_rest#*|}"
  _path="${_rest2%%|*}"
  [ -n "$_repo" ] && [ -n "$_url" ] && [ -n "$_path" ] || return 1
  case "$_repo" in
    *' '*|*'['*|*']'*) return 1 ;;
  esac
  return 0
}

load_submodule_entries() {
  _gitmodules="${1:-}"
  if [ -n "$_gitmodules" ] && [ -r "$_gitmodules" ]; then
    log "reading submodules from $_gitmodules" >&2
    parse_gitmodules_file "$_gitmodules"
    return 0
  fi
  if [ -r "$GITEA_SUBMODULES_CONF" ]; then
    log "reading submodules from $GITEA_SUBMODULES_CONF" >&2
    grep -v '^[[:space:]]*#' "$GITEA_SUBMODULES_CONF" | grep -v '^[[:space:]]*$'
    return 0
  fi
  return 1
}

write_gitmodules_snippet() {
  _out="$1"
  mkdir -p "$(dirname "$_out")"
  : > "$_out"
  while read -r line; do
    [ -n "$line" ] || continue
    _repo="${line%%|*}"
    _rest="${line#*|}"
    _url="${_rest%%|*}"
    _rest2="${_rest#*|}"
    _path="${_rest2%%|*}"
    _branch="${_rest2#*|}"
    case "$_branch" in
      "$_path") _branch="" ;;
    esac
    _gitea_url="$(gitea_public_repo_url_for "$GITEA_OWNER" "$_repo")"
    {
      printf '[submodule "%s"]\n' "$_path"
      printf '\tpath = %s\n' "$_path"
      printf '\turl = %s\n' "$_gitea_url"
      [ -n "$_branch" ] && printf '\tbranch = %s\n' "$_branch"
      printf '\n'
    } >> "$_out"
  done <<EOF
$(cat "$WORK_DIR/entries.list")
EOF
}

# --- main ---

gitea_load_config || exit 1
gitea_ensure_cli_access || exit 1

_gitmodules_arg=""
if [ $# -ge 1 ] && [ -n "$1" ]; then
  case "$1" in
    -h|--help)
      sed -n '2,18p' "$0"
      exit 0
      ;;
    *)
      _gitmodules_arg="$1"
      ;;
  esac
fi

gitea_org_ensure_androidcast "$GITEA_ORG" 2>/dev/null || true
GITEA_OWNER="${GITEA_OWNER:-$GITEA_ORG}"
if ! gitea_owner_exists "$GITEA_OWNER"; then
  _fb="$(gitea_pick_owner_username)"
  [ -n "$_fb" ] || die "no Gitea owner; set GITEA_OWNER=$GITEA_ORG"
  warn "GITEA_OWNER=$GITEA_OWNER not found; using $_fb"
  GITEA_OWNER="$_fb"
fi

gitea_prune_stale_tmp
if [ -n "$WORK_DIR" ]; then
  mkdir -p "$WORK_DIR"
else
  WORK_DIR="$(gitea_make_work_dir gitea-submodules)"
fi
trap 'gitea_rm_path "$WORK_DIR"' EXIT INT HUP TERM
: > "$WORK_DIR/entries.list"
if ! load_submodule_entries "$_gitmodules_arg" | while IFS= read -r _line; do
  [ -n "$_line" ] || continue
  is_valid_submodule_entry "$_line" || {
    warn "skipping invalid entry: $_line"
    continue
  }
  printf '%s\n' "$_line"
done > "$WORK_DIR/entries.list"; then
  die "no submodule list (pass .gitmodules path or use $GITEA_SUBMODULES_CONF)"
fi
[ -s "$WORK_DIR/entries.list" ] || die "no valid submodule entries parsed"

if command -v rc-service >/dev/null 2>&1; then
  rc-service gitea status 2>/dev/null | grep -qi started || rc-service gitea start 2>/dev/null || true
fi

log "owner=$GITEA_OWNER  interval=$GITEA_MIRROR_INTERVAL  ini=$GITEA_APP_INI"
_ok=0
_fail=0

while IFS= read -r line; do
  [ -n "$line" ] || continue
  _repo="${line%%|*}"
  _rest="${line#*|}"
  _upstream="${_rest%%|*}"
  _path="${_rest#*|}"
  _path="${_path%%|*}"

  log "mirror $_repo  <-  $_upstream"
  if git ls-remote "$_upstream" HEAD >/dev/null 2>&1; then
    log "  upstream reachable"
  else
    warn "  upstream not reachable from BE (mirror may still fail)"
  fi

  if gitea_mirror_pull_repo "$_upstream" "$_repo" "$GITEA_OWNER" "$GITEA_MIRROR_INTERVAL" "$WORK_DIR"; then
    log "  OK -> $(gitea_public_repo_url_for "$GITEA_OWNER" "$_repo")"
    _ok=$((_ok + 1))
  else
    warn "  FAILED $_repo"
    _fail=$((_fail + 1))
  fi
done < "$WORK_DIR/entries.list"

write_gitmodules_snippet "$SNIPPET_OUT"

log "mirrors ok=$_ok failed=$_fail"
log "Wrote .gitmodules snippet: $SNIPPET_OUT"
printf '\n'
cat "$SNIPPET_OUT"
printf '\n'

_main_repo_url="$(gitea_public_repo_url_for "$GITEA_OWNER" "android_cast")"
_rewrite_sh="$SCRIPT_DIR/gitea_submodule_local_rewrite.sh"
cat <<EOF

Keep upstream .gitmodules on canonical git (recommended):
  Gitea mirrors are independent; no remote .gitmodules edit required.
  After clone, point submodules at Gitea locally (stored in .git/config only):
    $_rewrite_sh --apply
  Or machine-wide url.insteadOf (any repo using the same upstream URLs):
    $_rewrite_sh --apply --global
  Then: git submodule update --init --recursive

Optional — rewrite committed .gitmodules on git://10.7.0.10/android_cast:
  Use the snippet above if every clone should default to Gitea URLs.

Clone main repo from Gitea:
  git clone $_main_repo_url
  cd android_cast && $_rewrite_sh --apply && git submodule update --init --recursive

Periodic sync all mirrors:
  sudo -u $GITEA_RUN_USER gitea -c $GITEA_APP_INI admin repo-sync-mirrors

EOF

[ "$_fail" -eq 0 ] || exit 1
