#!/usr/bin/env bash
#
# harbor-release-push.sh
#
# Pakt per release alle image-tars uit en pusht ze met skopeo naar de
# air-gapped Harbor.
#
#   ./harbor-release-push.sh <release-dir> [release.map]
#
# Verwacht in <release-dir>: de tar-bestanden plus (standaard) release.map.
# Credentials via omgevingsvariabelen:
#
#   export HARBOR_REGISTRY=harbor-kfc.ilionx-ocp.com
#   export HARBOR_USER=robot\$lakstraat
#   export HARBOR_PASS='...'
#
# Optioneel:
#   HARBOR_TLS_VERIFY=false   bij een self-signed certificaat
#   SKOPEO_ALL=true           multi-arch manifest lists meenemen
#   DRY_RUN=true              alleen tonen wat er zou gebeuren

set -Eeuo pipefail

RELEASE_DIR="${1:-}"
MAP_FILE="${2:-}"

REGISTRY="${HARBOR_REGISTRY:-harbor-kfc.ilionx-ocp.com}"
TLS_VERIFY="${HARBOR_TLS_VERIFY:-true}"
COPY_ALL="${SKOPEO_ALL:-false}"
DRY_RUN="${DRY_RUN:-false}"

WORK_DIR=""
FAILED=()
PUSHED=()

log()  { printf '[%s] %s\n' "$(date +%H:%M:%S)" "$*"; }
fail() { printf '[%s] FOUT: %s\n' "$(date +%H:%M:%S)" "$*" >&2; }

cleanup() {
    [[ -n "$WORK_DIR" && -d "$WORK_DIR" ]] && rm -rf "$WORK_DIR"
}
trap cleanup EXIT

usage() {
    sed -n '3,25p' "$0" | sed 's/^# \{0,1\}//'
    exit 1
}

[[ -z "$RELEASE_DIR" ]] && usage
[[ -d "$RELEASE_DIR" ]] || { fail "release-dir '$RELEASE_DIR' bestaat niet"; exit 1; }

RELEASE_DIR="$(cd "$RELEASE_DIR" && pwd)"
MAP_FILE="${MAP_FILE:-$RELEASE_DIR/release.map}"
[[ -f "$MAP_FILE" ]] || { fail "map-bestand '$MAP_FILE' niet gevonden"; exit 1; }

command -v skopeo >/dev/null || { fail "skopeo niet gevonden in PATH"; exit 1; }

if [[ -z "${HARBOR_USER:-}" || -z "${HARBOR_PASS:-}" ]]; then
    fail "HARBOR_USER en HARBOR_PASS moeten gezet zijn"
    exit 1
fi

# Detecteert het skopeo-transport van een uitgepakte map.
detect_transport() {
    local dir="$1"
    if [[ -f "$dir/oci-layout" ]]; then
        echo "oci"
    elif [[ -f "$dir/version" && -f "$dir/manifest.json" ]]; then
        echo "dir"
    else
        echo "onbekend"
    fi
}

log "Registry : $REGISTRY (tls-verify=$TLS_VERIFY, all=$COPY_ALL)"
log "Release  : $RELEASE_DIR"
log "Map      : $MAP_FILE"
[[ "$DRY_RUN" == "true" ]] && log "DRY RUN — er wordt niets gepusht"

WORK_DIR="$(mktemp -d /tmp/harbor-release.XXXXXX)"

while read -r tar_name repo_tag _deployment _container; do
    [[ -z "${tar_name:-}" || "${tar_name:0:1}" == "#" ]] && continue

    tar_path="$RELEASE_DIR/$tar_name"
    target="$REGISTRY/$repo_tag"

    if [[ ! -f "$tar_path" ]]; then
        fail "tar ontbreekt: $tar_path"
        FAILED+=("$repo_tag (tar ontbreekt)")
        continue
    fi

    log "── $repo_tag"

    extract_dir="$WORK_DIR/$(basename "$tar_name" .tar)"
    mkdir -p "$extract_dir"

    if ! tar -xf "$tar_path" -C "$extract_dir"; then
        fail "uitpakken mislukt: $tar_name"
        FAILED+=("$repo_tag (uitpakken)")
        continue
    fi

    # De tar bevat vaak één map; zak daar dan automatisch in.
    src_dir="$extract_dir"
    shopt -s nullglob dotglob
    entries=("$extract_dir"/*)
    shopt -u nullglob dotglob
    if [[ ${#entries[@]} -eq 1 && -d "${entries[0]}" ]]; then
        src_dir="${entries[0]}"
    fi

    transport="$(detect_transport "$src_dir")"
    case "$transport" in
        oci) source_ref="oci:$src_dir" ;;
        dir) source_ref="dir:$src_dir" ;;
        *)
            fail "onbekende inhoud in $tar_name (geen oci-layout of dir-transport)"
            FAILED+=("$repo_tag (formaat)")
            continue
            ;;
    esac

    copy_args=(
        --dest-creds "$HARBOR_USER:$HARBOR_PASS"
        --dest-tls-verify="$TLS_VERIFY"
        --retry-times 3
    )
    [[ "$COPY_ALL" == "true" ]] && copy_args+=(--all)

    log "   $transport → $target"

    if [[ "$DRY_RUN" == "true" ]]; then
        PUSHED+=("$target")
        continue
    fi

    if skopeo copy "${copy_args[@]}" "$source_ref" "docker://$target"; then
        PUSHED+=("$target")
        log "   ok"
    else
        fail "push mislukt: $target"
        FAILED+=("$repo_tag (push)")
    fi

    rm -rf "$extract_dir"
done < "$MAP_FILE"

echo
log "Gepusht: ${#PUSHED[@]}"
for image in "${PUSHED[@]}"; do echo "   $image"; done

if [[ ${#FAILED[@]} -gt 0 ]]; then
    echo
    fail "Mislukt: ${#FAILED[@]}"
    for item in "${FAILED[@]}"; do echo "   $item" >&2; done
    exit 1
fi

echo
log "Alle images staan in Harbor."
