#!/bin/ash
# Discover git submodules (upstream URL + pinned SHA) from a checkout.
# shellcheck shell=sh

# Space-separated host/prefix patterns treated as "ours" (skipped for external mirrors).
GITEA_LOCAL_URL_PATTERNS="${GITEA_LOCAL_URL_PATTERNS:-10.7.0.10 10.7.16. apps.f0xx.org f0xx.org 127.0.0.1 localhost}"

gitea_submodule_is_local_url() {
  _url="$1"
  case "$_url" in
    /*|./*|../*) return 0 ;;
  esac
  for _pat in $GITEA_LOCAL_URL_PATTERNS; do
    case "$_url" in
      *"$_pat"*) return 0 ;;
    esac
  done
  return 1
}

gitea_submodule_is_external_url() {
  gitea_submodule_is_local_url "$1" && return 1
  return 0
}

# .gitmodules -> repo|url|path|branch (repo = basename of path). stdout only.
gitea_submodule_parse_gitmodules() {
  _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|url|path|sha[|branch] — external entries from .gitmodules (sha may be "-" if unknown).
gitea_submodule_discover_from_gitmodules() {
  _gitmodules="$1"
  _repo_dir="${2:-}"
  _ref="${3:-HEAD}"
  [ -r "$_gitmodules" ] || return 1

  gitea_submodule_parse_gitmodules "$_gitmodules" | while IFS= 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_submodule_is_external_url "$_url" || continue

    _sha="-"
    if [ -n "$_repo_dir" ] && command -v git >/dev/null 2>&1 \
      && git -C "$_repo_dir" rev-parse --verify "$_ref" >/dev/null 2>&1; then
      _got="$(git -C "$_repo_dir" rev-parse "$_ref:$_path" 2>/dev/null)" || _got=""
      case "$_got" in
        ??000000000000000000000000000000000000) _sha="-" ;;
        ????????????????????????????????????????*) _sha="$_got" ;;
      esac
    fi

    if [ -n "$_branch" ]; then
      printf '%s|%s|%s|%s|%s\n' "$_repo" "$_url" "$_path" "$_sha" "$_branch"
    else
      printf '%s|%s|%s|%s\n' "$_repo" "$_url" "$_path" "$_sha"
    fi
  done
}

# repo|url|path|sha[|branch] for each external submodule with a gitlink at REF.
gitea_submodule_discover_external() {
  _repo_dir="$1"
  _ref="${2:-HEAD}"
  _gitmodules="$_repo_dir/.gitmodules"

  command -v git >/dev/null 2>&1 || return 1
  git -C "$_repo_dir" rev-parse --verify "$_ref" >/dev/null 2>&1 || return 1
  [ -r "$_gitmodules" ] || return 1

  gitea_submodule_discover_from_gitmodules "$_gitmodules" "$_repo_dir" "$_ref" \
    | while IFS= read -r _line; do
      _sha="${_line##*|}"
      case "$_sha" in
        -) continue ;;
      esac
      printf '%s\n' "$_line"
    done
}

# repo|url|path|sha[|branch] from submodules.defaults.conf (sha resolved when possible).
gitea_submodule_load_defaults() {
  _conf="$1"
  _repo_dir="${2:-}"
  _ref="${3:-HEAD}"
  [ -r "$_conf" ] || return 1

  grep -v '^[[:space:]]*#' "$_conf" | grep -v '^[[:space:]]*$' | while IFS= 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_submodule_is_external_url "$_url" || continue
    _sha="-"
    if [ -n "$_repo_dir" ] && command -v git >/dev/null 2>&1 \
      && git -C "$_repo_dir" rev-parse --verify "$_ref" >/dev/null 2>&1; then
      _got="$(git -C "$_repo_dir" rev-parse "$_ref:$_path" 2>/dev/null)" || _got=""
      case "$_got" in
        ????????????????????????????????????????*) _sha="$_got" ;;
      esac
    fi
    if [ -n "$_branch" ]; then
      printf '%s|%s|%s|%s|%s\n' "$_repo" "$_url" "$_path" "$_sha" "$_branch"
    else
      printf '%s|%s|%s|%s\n' "$_repo" "$_url" "$_path" "$_sha"
    fi
  done
}

# Merge discovery sources; first win per repo name. stdout: repo|url|path|sha[|branch]
gitea_submodule_collect_entries() {
  _repo_dir="${1:-}"
  _ref="${2:-HEAD}"
  _gitmodules="${3:-}"
  _defaults="${4:-}"

  _work="$(mktemp /tmp/gitea-submods-XXXXXX)"

  if [ -n "$_gitmodules" ] && [ -r "$_gitmodules" ]; then
    gitea_submodule_discover_from_gitmodules "$_gitmodules" "$_repo_dir" "$_ref" >> "$_work" 2>/dev/null || true
  elif [ -n "$_repo_dir" ] && [ -r "$_repo_dir/.gitmodules" ]; then
    gitea_submodule_discover_from_gitmodules "$_repo_dir/.gitmodules" "$_repo_dir" "$_ref" >> "$_work" 2>/dev/null || true
  fi

  # Use defaults only when .gitmodules produced nothing (never merge extras on top).
  if [ ! -s "$_work" ] && [ -n "$_defaults" ] && [ -r "$_defaults" ]; then
    gitea_submodule_load_defaults "$_defaults" "$_repo_dir" "$_ref" >> "$_work" 2>/dev/null || true
  fi

  awk -F'|' '!seen[$1]++' "$_work"
  rm -f "$_work"
}

gitea_submodule_entry_valid() {
  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
}
