#!/usr/bin/env bash
set -euox pipefail

cd "$(dirname "$0")"

DRY_RUN=false

parse_args() {
    while getopts 'd' OPTION; do
        case "$OPTION" in
        d)
            DRY_RUN=true
            ;;
        ?)
            exit 1
            ;;
        esac
    done
}

parse_args "$@"

ARCHITECTURES=(
    amd64
    arm
    arm64
    ppc64le
    s390x
    mips64le
)

# Prepare the system
REGISTRY=${REGISTRY:-gcr.io/k8s-staging-cri-tools}
QEMUVERSION=5.2.0-2

export DOCKER_CLI_EXPERIMENTAL=enabled
if [[ $DRY_RUN != true ]]; then
    gcloud auth configure-docker
fi
docker run --rm --privileged multiarch/qemu-user-static:$QEMUVERSION --reset -p yes >/dev/null
BUILDER=$(docker buildx create --use)

cleanup() {
    docker buildx rm "$BUILDER"
}

trap cleanup EXIT

build_image() {
    DIR=$1
    IMAGE=$2
    ARGS=("${@:3}")

    IMAGE_NAMES=()
    for ARCH in "${ARCHITECTURES[@]}"; do
        FULL_IMAGE_NAME="$REGISTRY/$IMAGE-$ARCH:latest"
        IMAGE_NAMES+=("$FULL_IMAGE_NAME")

        docker buildx build \
            --pull \
            --load \
            --platform "linux/$ARCH" \
            -t "$FULL_IMAGE_NAME" \
            "${ARGS[@]}" \
            "$DIR"

        if [[ $DRY_RUN != true ]]; then
            docker push "$FULL_IMAGE_NAME"
        fi
    done

    if [[ $DRY_RUN != true ]]; then
        MANIFEST="$REGISTRY/$IMAGE:latest"
        docker manifest create --amend "$MANIFEST" "${IMAGE_NAMES[@]}"
        for ARCH in "${ARCHITECTURES[@]}"; do
            FULL_IMAGE_NAME="$REGISTRY/$IMAGE-$ARCH:latest"
            docker manifest annotate --arch "$ARCH" "$MANIFEST" "$FULL_IMAGE_NAME"
        done
        docker manifest push "$MANIFEST"
    fi
}

# Build the user images
declare -A IMAGE_USERS
IMAGE_USERS=(
    ["test-image-user-uid"]="1002"
    ["test-image-user-username"]="www-data"
    ["test-image-user-uid-group"]="1003:1004"
    ["test-image-user-username-group"]="www-data:1004"
)

for IMAGE in "${!IMAGE_USERS[@]}"; do
    USER=${IMAGE_USERS[$IMAGE]}
    build_image ./image-user "$IMAGE" --build-arg "USER=$USER"
done

# Build the user with pre-defined group image
build_image ./image-predefined-group test-image-predefined-group

# Build the hostnet image
build_image ./hostnet-nginx hostnet-nginx

if [[ $DRY_RUN != true ]]; then
    # Build the windows images
    declare -A IMAGE_WINDOWS
    IMAGE_WINDOWS=(
        ["win-test-image-1"]="latest"
        ["win-test-image-2"]="latest"
        ["win-test-image-3"]="latest"
        ["win-test-image-latest"]="latest"
        ["win-test-image-digest"]="latest"
    )
    WIN_DIR=image-test-win
    for IMAGE in "${!IMAGE_WINDOWS[@]}"; do
        TAG=${IMAGE_WINDOWS[$IMAGE]}
        touch "$WIN_DIR/$IMAGE"
        docker buildx build \
            --pull --push \
            --platform "windows/amd64" \
            --build-arg "TEST=$IMAGE" \
            -t "$REGISTRY/$IMAGE:$TAG" \
            $WIN_DIR
        rm -f "$WIN_DIR/$IMAGE"
    done

    IMAGE=win-test-image-tags
    touch "$WIN_DIR/$IMAGE"
    docker buildx build \
        --pull --push \
        --platform "windows/amd64" \
        --build-arg "TEST=$IMAGE" \
        -t "$REGISTRY/$IMAGE:1" \
        -t "$REGISTRY/$IMAGE:2" \
        -t "$REGISTRY/$IMAGE:3" \
        $WIN_DIR
    rm -f "$WIN_DIR/$IMAGE"

    IMAGE=win-test-image-tag
    touch "$WIN_DIR/$IMAGE"
    docker buildx build \
        --pull --push \
        --platform "windows/amd64" \
        --build-arg "TEST=$IMAGE" \
        -t "$REGISTRY/$IMAGE:test" \
        -t "$REGISTRY/$IMAGE:all" \
        $WIN_DIR
    rm -f "$WIN_DIR/$IMAGE"
fi

# Build the other test images
IMAGE_TEST=(
    test-image-1
    test-image-2
    test-image-3
    test-image-latest
    test-image-digest
)
DIR=image-test
for IMAGE in "${IMAGE_TEST[@]}"; do
    touch "$DIR/$IMAGE"
    build_image "$DIR" "$IMAGE" --build-arg "TEST=$IMAGE"
    rm -f "$DIR/$IMAGE"
done

# Build test-image-tags
IMAGE_NAMES=()
IMAGE=test-image-tags
TAGS=(1 2 3)
touch "$DIR/same-image"
for ARCH in "${ARCHITECTURES[@]}"; do
    for TAG in "${TAGS[@]}"; do
        FULL_IMAGE_NAME="$REGISTRY/$IMAGE-$ARCH:$TAG"
        IMAGE_NAMES+=("$FULL_IMAGE_NAME")

        docker buildx build \
            --pull \
            --load \
            --platform "linux/$ARCH" \
            -t "$FULL_IMAGE_NAME" \
            --build-arg TEST=same-image \
            "$DIR"

        if [[ $DRY_RUN != true ]]; then
            docker push "$FULL_IMAGE_NAME"
        fi
    done
done
rm -f "$DIR/same-image"

if [[ $DRY_RUN != true ]]; then
    for TAG in "${TAGS[@]}"; do
        MANIFEST="$REGISTRY/$IMAGE:$TAG"
        docker manifest create --amend "$MANIFEST" "${IMAGE_NAMES[@]}"
        for ARCH in "${ARCHITECTURES[@]}"; do
            FULL_IMAGE_NAME="$REGISTRY/$IMAGE-$ARCH:$TAG"
            docker manifest annotate --arch "$ARCH" "$MANIFEST" "$FULL_IMAGE_NAME"
        done
        docker manifest push "$MANIFEST"
    done
fi

# Build test-image-tag
IMAGE_NAMES=()
IMAGE=test-image-tag
TAGS=(test all)
for TAG in "${TAGS[@]}"; do
    touch "$DIR/$TAG"
    for ARCH in "${ARCHITECTURES[@]}"; do
        FULL_IMAGE_NAME="$REGISTRY/$IMAGE-$ARCH:$TAG"
        IMAGE_NAMES+=("$FULL_IMAGE_NAME")

        docker buildx build \
            --pull \
            --load \
            --platform "linux/$ARCH" \
            -t "$FULL_IMAGE_NAME" \
            --build-arg "TEST=$TAG" \
            "$DIR"

        if [[ $DRY_RUN != true ]]; then
            docker push "$FULL_IMAGE_NAME"
        fi
    done
    rm -f "$DIR/$TAG"

    if [[ $DRY_RUN != true ]]; then
        MANIFEST="$REGISTRY/$IMAGE:$TAG"
        docker manifest create --amend "$MANIFEST" "${IMAGE_NAMES[@]}"
        for ARCH in "${ARCHITECTURES[@]}"; do
            FULL_IMAGE_NAME="$REGISTRY/$IMAGE-$ARCH:$TAG"
            docker manifest annotate --arch "$ARCH" "$MANIFEST" "$FULL_IMAGE_NAME"
        done
        docker manifest push "$MANIFEST"
    fi
done
