#!/bin/sh

set -eu
set -f

usage() {
  cat <<'USAGE'
Linux by Intent source fetch helper (POSIX sh + curl + pinned git archives)

Usage:
  fetch-sources.sh [-d DIRECTORY] [-m MANIFEST] [-f] [URL [OUTPUT_NAME] ...]

Options:
  -d, --directory DIR  destination directory (default: $LBI_SOURCES or ./sources)
  -m, --manifest FILE  read source URLs from FILE
  -f, --force          re-download files even when they already exist
  -h, --help           show this help text

Manifest format:
  One entry per line: URL [OUTPUT_NAME]
  Git snapshots use: git+REPOSITORY_URL#REF OUTPUT_NAME.tar.gz
  Blank lines and lines beginning with # are ignored.

Direct URL format:
  A URL may be followed by an output filename. The output filename must not
  look like another URL.
USAGE
}

fail() {
  printf 'ERROR: %s\n' "$*" >&2
  exit 1
}

require_tool() {
  tool_name=$1
  if command -v "$tool_name" >/dev/null 2>&1; then
    return 0
  fi

  fail "$tool_name is required but was not found in PATH"
}

download_one() {
  source_url=$1
  output_name=${2-}

  case "$source_url" in
    git+*)
      download_git_archive "$source_url" "$output_name"
      return 0
      ;;
  esac

  if [ -z "$output_name" ]; then
    output_name=${source_url##*/}
    output_name=${output_name%%\?*}
    output_name=${output_name%%\#*}
  fi

  if [ -z "$output_name" ] || [ "$output_name" = "/" ]; then
    fail "could not determine output file name for URL: $source_url"
  fi

  destination="$download_dir/$output_name"

  if [ "$force_download" -eq 0 ] && [ -s "$destination" ]; then
    printf 'SKIP: %s already exists\n' "$destination"
    return 0
  fi

  printf 'FETCH: %s\n' "$source_url"
  curl --fail --location --retry 3 --continue-at - --output "$destination" "$source_url"
}

download_git_archive() {
  source_url=$1
  output_name=$2
  git_spec=${source_url#git+}

  case "$git_spec" in
    *#*)
      git_ref=${git_spec##*#}
      git_url=${git_spec%#*}
      ;;
    *)
      fail "git source requires a pinned ref after #: $source_url"
      ;;
  esac

  if [ -z "$git_url" ] || [ -z "$git_ref" ]; then
    fail "git source requires both repository URL and ref: $source_url"
  fi

  if [ -z "$output_name" ]; then
    repo_name=${git_url##*/}
    repo_name=${repo_name%.git}
    short_ref=$(printf '%s\n' "$git_ref" | cut -c1-12)
    output_name="$repo_name-$short_ref.tar.gz"
  fi

  destination="$download_dir/$output_name"

  if [ "$force_download" -eq 0 ] && [ -s "$destination" ]; then
    printf 'SKIP: %s already exists\n' "$destination"
    return 0
  fi

  require_tool git
  require_tool gzip

  archive_prefix=${output_name%.tar.gz}
  if [ "$archive_prefix" = "$output_name" ]; then
    archive_prefix=${output_name%.tgz}
  fi
  if [ "$archive_prefix" = "$output_name" ]; then
    archive_prefix=${output_name%.*}
  fi

  tmpdir=$(mktemp -d 2>/dev/null || mktemp -d -t lbi-fetch-git)

  printf 'FETCH: %s\n' "$source_url"
  if ! git clone --quiet "$git_url" "$tmpdir/repo"; then
    rm -rf "$tmpdir"
    fail "git clone failed for $git_url"
  fi

  if ! git -C "$tmpdir/repo" checkout --quiet "$git_ref"; then
    rm -rf "$tmpdir"
    fail "git checkout failed for $git_ref"
  fi

  if ! git -C "$tmpdir/repo" archive --format=tar --prefix="$archive_prefix/" "$git_ref" | gzip -n > "$destination.part"; then
    rm -rf "$tmpdir"
    rm -f "$destination.part"
    fail "git archive failed for $git_ref"
  fi

  mv "$destination.part" "$destination"
  rm -rf "$tmpdir"
}

download_from_manifest() {
  manifest_path=$1

  if [ ! -f "$manifest_path" ]; then
    fail "manifest file was not found: $manifest_path"
  fi

  while IFS= read -r line || [ -n "$line" ]; do
    set -- $line

    if [ "$#" -eq 0 ]; then
      continue
    fi

    case "$1" in
      \#*)
        continue
        ;;
    esac

    source_url=$1
    output_name=""

    if [ "$#" -ge 2 ]; then
      output_name=$2
    fi

    download_one "$source_url" "$output_name"
    had_input=1
  done < "$manifest_path"
}

looks_like_source_url() {
  case "$1" in
    git+*|*://*)
      return 0
      ;;
  esac

  return 1
}

download_dir=${LBI_SOURCES:-"$PWD/sources"}
manifest_file=""
force_download=0
had_input=0

while [ "$#" -gt 0 ]; do
  case "$1" in
    -d|--directory)
      if [ "$#" -lt 2 ]; then
        fail "missing argument for $1"
      fi
      download_dir=$2
      shift 2
      ;;
    -m|--manifest)
      if [ "$#" -lt 2 ]; then
        fail "missing argument for $1"
      fi
      manifest_file=$2
      shift 2
      ;;
    -f|--force)
      force_download=1
      shift
      ;;
    -h|--help)
      usage
      exit 0
      ;;
    --)
      shift
      break
      ;;
    -*)
      fail "unknown option: $1"
      ;;
    *)
      break
      ;;
  esac
done

require_tool curl
mkdir -p "$download_dir"

if [ -n "$manifest_file" ]; then
  download_from_manifest "$manifest_file"
fi

while [ "$#" -gt 0 ]; do
  source_url=$1
  output_name=""
  shift

  if ! looks_like_source_url "$source_url"; then
    fail "expected a source URL, got: $source_url"
  fi

  if [ "$#" -gt 0 ] && ! looks_like_source_url "$1"; then
    output_name=$1
    shift
  fi

  download_one "$source_url" "$output_name"
  had_input=1
done

if [ "$had_input" -eq 0 ]; then
  fail "no sources were provided; pass URLs and/or --manifest FILE"
fi

printf 'DONE: source archives are in %s\n' "$download_dir"
