#!/usr/bin/env bash

# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

set -o errexit
set -o nounset
set -o pipefail

DEFAULT_REGISTRY_IMAGE=registry:2
DEFAULT_REGISTRY_NAME=kind-registry
DEFAULT_REGISTRY_PORT=5000
DEFAULT_CLUSTER_NAME=kind
DEFAULT_CPU=2
DEFAULT_MEMORY=12
DEFAULT_DISK=60

show_help() {
cat << EOF
Usage: $(basename "$0") <options>

    -h, --help                              Display help
        --cpu                               Number of CPUs to be allocated to the virtual machine (default: $DEFAULT_CPU). For Mac OS only
        --disk                              Size of the disk in GiB to be allocated to the virtual machine (default: $DEFAULT_DISK). For Mac OS only
        --memory                            Size of the memory in GiB to be allocated to the virtual machine (default: $DEFAULT_MEMORY). For Mac OS only
        --registry-image                    The registry image to use (default: $DEFAULT_REGISTRY_IMAGE)
        --registry-name                     The registry name to use (default: $DEFAULT_REGISTRY_NAME)
        --registry-port                     The local port used to bind the registry (default: $DEFAULT_REGISTRY_PORT)
        --registry-delete                   Enable delete operations on the registry (default is false)
        -n, --cluster-name                  The name of the cluster to create (default: $DEFAULT_CLUSTER_NAME)"
        --document                          Document the local registry

EOF
}

main() {
    local registry_image="$DEFAULT_REGISTRY_IMAGE"
    local registry_name="$DEFAULT_REGISTRY_NAME"
    local registry_port="$DEFAULT_REGISTRY_PORT"
    local registry_delete="false"
    local cluster_name="$DEFAULT_CLUSTER_NAME"
    local cpu="$DEFAULT_CPU"
    local disk="$DEFAULT_DISK"
    local memory="$DEFAULT_MEMORY"
    local document=false

    parse_command_line "$@"

    if [[ "$document" = "false" ]]
    then
        install_docker
        create_registry
        connect_registry
        create_kind_config
    else
        document
    fi

}

parse_command_line() {
    while :; do
        case "${1:-}" in
            -h|--help)
                show_help
                exit
                ;;
            --cpu)
                if [[ -n "${2:-}" ]]; then
                    cpu="$2"
                    shift
                else
                    echo "ERROR: '--cpu' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            --disk)
                if [[ -n "${2:-}" ]]; then
                    disk="$2"
                    shift
                else
                    echo "ERROR: '--disk' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            --memory)
                if [[ -n "${2:-}" ]]; then
                    memory="$2"
                    shift
                else
                    echo "ERROR: '--memory' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            --registry-image)
                if [[ -n "${2:-}" ]]; then
                    registry_image="$2"
                    shift
                else
                    echo "ERROR: '--registry-image' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            --registry-name)
                if [[ -n "${2:-}" ]]; then
                    registry_name="$2"
                    shift
                else
                    echo "ERROR: '--registry-name' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            --registry-port)
                if [[ -n "${2:-}" ]]; then
                    registry_port="$2"
                    shift
                else
                    echo "ERROR: '--registry-port' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            --registry-delete)
                if [[ -n "${2:-}" ]]; then
                    registry_delete="$2"
                    shift
                else
                    echo "ERROR: '--registry-delete' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            -n|--cluster-name)
                if [[ -n "${2:-}" ]]; then
                    cluster_name="$2"
                    shift
                else
                    echo "ERROR: '-n|--cluster-name' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            --document)
                if [[ -n "${2:-}" ]]; then
                    document="$2"
                    shift
                else
                    echo "ERROR: '--document' cannot be empty." >&2
                    show_help
                    exit 1
                fi
                ;;
            *)
                break
                ;;
        esac

        shift
    done
}

install_docker() {
    if [ "$RUNNER_OS" == "macOS" ] && ! [ -x "$(command -v docker)" ]; then
        echo 'Installing docker...'
        brew install docker docker-buildx colima
        mkdir -p ~/.docker/cli-plugins
        ln -sfn /usr/local/opt/docker-buildx/bin/docker-buildx ~/.docker/cli-plugins/docker-buildx
        colima start --cpu "$cpu" --memory "$memory" --disk "$disk"
    fi
}

create_registry() {
    echo "Creating registry \"$registry_name\" on port $registry_port from image \"$registry_image\" with delete enabled $registry_delete ..."
    docker run -d --restart=always -p "${registry_port}:5000" -e "REGISTRY_STORAGE_DELETE_ENABLED=${registry_delete}" --name "${registry_name}" $registry_image
> /dev/null

    # Adding registry to /etc/hosts
    echo "127.0.0.1 $registry_name" | sudo tee -a /etc/hosts

    # Exporting the registry location for subsequent jobs
    echo "KIND_REGISTRY=${registry_name}:${registry_port}" >> $GITHUB_ENV
}

connect_registry() {
    echo 'Connecting registry to the "kind" network...'
    docker network create kind
    docker network connect "kind" "${registry_name}"
}

create_kind_config() {
    sudo mkdir -p /etc/kind-registry
    cat <<EOF | sudo dd of=/etc/kind-registry/config.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
containerdConfigPatches:
- |-
  [plugins."io.containerd.grpc.v1.cri".registry.mirrors."${registry_name}:${registry_port}"]
    endpoint = ["http://${registry_name}:${registry_port}"]
EOF
    sudo chmod a+r /etc/kind-registry/config.yaml
}

document() {
    # Document the local registry
    # https://github.com/kubernetes/enhancements/tree/master/keps/sig-cluster-lifecycle/generic/1755-communicating-a-local-registry
    cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: ConfigMap
metadata:
  name: local-registry-hosting
  namespace: kube-public
data:
  localRegistryHosting.v1: |
    host: "${registry_name}:${registry_port}"
    hostFromClusterNetwork: "${registry_name}:${registry_port}"
    help: "https://kind.sigs.k8s.io/docs/user/local-registry/"
EOF
}

main "$@"