#!/usr/bin/env bash
# vim:et:ts=2:sts=2:sw=2

# Get absolute repository root (especially when symlinked)
ROOT="$(realpath "$(dirname \"$(dirname \"$(readlink -f \"${BASH_SOURCE[0]}\")\")\")")"

# Load accompanying bash library
source "$ROOT/lib/lib.bash"

BUNDLE_NAME="$1"
shift
PKGS_INPUT=($@)

if [ -z "$BUNDLE_NAME" ] || [ ${#PKGS_INPUT[@]} -eq 0 ] || [ "$1" = "-h" ] || [ "$1" = "--help" ]; then
  say "
  USAGE:
    $(g "${BASH_SOURCE##*/}")  $(c bundle-name)  $(c pkg1)  [$(c /path/to/pkg2.pkg.tar.zst) ...]

  DESCRIPTION:
    Creates a package bundle archive containing specified packages and their
    dependencies. It accepts both repository package names (e.g., 'supertuxkart') and
    paths to pre-built package files (AUR).

    For AUR packages, you must build them first with 'makepkg' and provide the
    path to the resulting '.pkg.tar.zst' file.

  EXAMPLE:
    # Build the AUR package first
    git clone https://aur.archlinux.org/xmoto.git && cd xmoto && makepkg -sr
    
    # Then create the bundle
    sudo ${BASH_SOURCE##*/} my-tools-bundle ../xmoto/xmoto-*.pkg.tar.zst xmoto
"
  exit 1
fi

# Exit now if not run as admin
assert-is-admin
say "This script will need root access via $(c sudo)"
sudo echo thank you

if [[ ! "$BUNDLE_NAME" =~ -bundle$ ]]; then
  warn "Bundle name $(c \"$BUNDLE_NAME\") does not end with '-bundle'."
  warn "It may not be installable with tl-comp-pull."
fi

DEST_DIR="/srv/packages"
run mkdir -p "$DEST_DIR"

if [ -f "$DEST_DIR/$BUNDLE_NAME.tar.gz" ]; then
  err "Bundle $(c \"$DEST_DIR/$BUNDLE_NAME.tar.gz\") already exists...exiting."
  exit 1
fi

REPO_PKGS=()
LOCAL_PKG_FILES=()

say "Processing package list..."
for pkg_input in "${PKGS_INPUT[@]}"; do
  # Check if it is a pre-built package file (AUR)
  if [[ -f "$pkg_input" && "$pkg_input" == *.pkg.tar.* ]]; then
    abspath=$(realpath "$pkg_input")
    say "Found local package: $(c "$(basename "$abspath")")"
    LOCAL_PKG_FILES+=("$abspath")

    # Get its dependencies and add them to the list of repo packages to fetch
    DEPS=$(pacman -Qip "$abspath" | awk -F': ' '/^Depends On/ {print $2}')
    if [ -n "$DEPS" ]; then
      CLEAN_DEPS=$(echo "$DEPS" | sed -e 's/[<>=][^[:space:]]*//g' -e 's/ *([^)]*)//g')
      read -ra CLEAN_DEPS <<<"$CLEAN_DEPS" # split into array
      say "  Adding dependencies: $(c "${CLEAN_DEPS[*]}")"
      for dep in "${CLEAN_DEPS[@]}"; do
        if ! pacman -Qi "$dep" &>/dev/null; then
          REPO_PKGS+=("$dep")
        fi
      done
    fi

  else
    # This is a repository package name
    say "Found repo package: $(c \"$pkg_input\")"
    REPO_PKGS+=("$pkg_input")
  fi
done

ALL_PKG_FILES=("${LOCAL_PKG_FILES[@]}")
TMP_DIR=$(mktemp -d)
cleanup() { run rm -rf "$TMP_DIR"; }

if [ ${#REPO_PKGS[@]} -gt 0 ]; then
  say "Resolving full dependency tree..."
  mapfile -t FULL_DEPS < <(pacman -Sp --print-format %n "${REPO_PKGS[@]}")
  REPO_PKGS=("${FULL_DEPS[@]}")

  say "Downloading repo packages and dependencies..."
  sudo pacman -Sw --cachedir "$TMP_DIR" --noconfirm --needed "${REPO_PKGS[@]}"

  mapfile -t REPO_PKG_FILES < <(
    pacman -Swp --cachedir "$TMP_DIR" --noconfirm --needed "${REPO_PKGS[@]}" \
      | sed 's|^file://||'
  )

  ALL_PKG_FILES+=("${REPO_PKG_FILES[@]}")
fi

if [ ${#ALL_PKG_FILES[@]} -eq 0 ]; then
  err "No packages found to bundle. Check package names and paths."
  exit 1
fi

# Deduplicate package files
readarray -t UNIQUE_PKG_FILES < <(printf "%s\n" "${ALL_PKG_FILES[@]}" | sort -u)

say "The following package files will be bundled:"
for f in "${UNIQUE_PKG_FILES[@]}"; do
  say "  - $(basename "$f")"
done

say "Staging packages in a temporary directory..."
for f in "${UNIQUE_PKG_FILES[@]}"; do
  if [ "$(dirname "$f")" != "$TMP_DIR" ]; then
    cp -v "$f" "$TMP_DIR/"
  fi
done

# run cp -v "${UNIQUE_PKG_FILES[@]}" "$TMP_DIR/"

ARCHIVE_PATH="$DEST_DIR/$BUNDLE_NAME.tar.gz"
say "Creating bundle archive at $(c \"$ARCHIVE_PATH\")"
run tar -czf "$ARCHIVE_PATH" -C "$TMP_DIR" .

say "$(g \"Success!\") Bundle created."
say "Distribute $(c \"$ARCHIVE_PATH\") on your upstream server."
