#!/usr/bin/env bash

# "To provide additional docker-compose args, set the COMPOSE var. Ex:
# COMPOSE="-f FILE_PATH_HERE"

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

ERROR() {
    echo -e "\e[101m\e[97m[ERROR]\e[49m\e[39m" "$@"
}

WARNING() {
    echo -e "\e[101m\e[97m[WARNING]\e[49m\e[39m" "$@"
}

INFO() {
    echo -e "\e[104m\e[97m[INFO]\e[49m\e[39m" "$@"
}

exists() {
    type "$1" > /dev/null 2>&1
}

# Change directory to the source directory of this script. Taken from:
# https://stackoverflow.com/a/246128/3858681
pushd "$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )"

HELP=0
INIT_ONLY=0
COMPOSE=${COMPOSE:-""}
SUBNET=${SUBNET:-"172.19.0.0/24"}
PROXY_SUBNET=${PROXY_SUBNET:-"172.19.1.0/24"}
NODES=${NODES:-5}
RUN_AS_DAEMON=0
INCLUDE_PROXY_NODES=0
POSITIONAL=()

while [[ $# -gt 0 ]]
do
    key="$1"

    case $key in
        -h|--help)
            HELP=1
            shift # past argument
            ;;
        --init-only)
            INIT_ONLY=1
            shift # past argument
            ;;
        --compose)
            COMPOSE="-f $2"
            shift # past argument
            shift # past value
            ;;
        --subnet)
            SUBNET="$2"
            shift # past argument
            shift # past value
            ;;
        -n|--nodes)
            NODES="$2"
            shift # past argument
            shift # past value
            ;;
        -d|--daemon)
            INFO "Running docker-compose as daemon"
            RUN_AS_DAEMON=1
            shift # past argument
            ;;
        --ssh-proxy)
            INFO "Include SSH proxy nodes"
            INCLUDE_PROXY_NODES=1
            shift # past argument
            ;;
        --proxy-subnet)
            PROXY_SUBNET="$2"
            shift # past argument
            shift # past value
            ;;
        *)
            POSITIONAL+=("$1")
            ERROR "unknown option $1"
            shift # past argument
            ;;
    esac
done

# comment because ERROR:
# ./up.sh: line 79: POSITIONAL[@]: unbound variable]
# set -- "${POSITIONAL[@]}" # restore positional parameters

if [ "${HELP}" -eq 1 ]; then
    echo "Usage: $0 [OPTION]"
    echo "  --help                                                Display this message"
    echo "  --init-only                                           Initializes ssh-keys, but does not call docker-compose"
    echo "  --daemon                                              Runs docker-compose in the background"
    echo "  --compose PATH                                        Path to an additional docker-compose yml config."
    echo "  --subnet SUBNET                                       Subnet in 24 bit netmask"
    echo "  --nodes NODES                                         Start how much nodes"
    echo "  --ssh-proxy                                           Start with ssh proxy nodes"
    echo "  --proxy-subnet PROXY_SUBNET                           Proxy subnet in 24 bit netmask"
    echo "To provide multiple additional docker-compose args, set the COMPOSE var directly, with the -f flag. Ex: COMPOSE=\"-f FILE_PATH_HERE -f ANOTHER_PATH\" ./up.sh'"
    exit 0
fi

exists ssh-keygen || { ERROR "Please install ssh-keygen (apt-get install openssh-client)"; exit 1; }
exists perl || { ERROR "Please install perl (apt-get install perl)"; exit 1; }

# Generate SSH keys for the control node
if [ ! -f ./secret/node.env ]; then
    INFO "Generating key pair"
    mkdir -p secret
    ssh-keygen -t rsa -N "" -f ./secret/id_rsa

    INFO "Generating ./secret/control.env"
    { echo "# generated by tiup-cluster/docker/up.sh, parsed by tiup-cluster/docker/control/bashrc";
      echo "# NOTE: newline is expressed as ↩";
      echo "SSH_PRIVATE_KEY=$(perl -p -e "s/\n/↩/g" < ./secret/id_rsa)";
      echo "SSH_PUBLIC_KEY=$(cat ./secret/id_rsa.pub)"; } >> ./secret/control.env

    INFO "Generating ./secret/node.env"
    { echo "# generated by tiup-cluster/docker/up.sh, parsed by the \"tutum/debian\" docker image entrypoint script";
      echo "ROOT_PASS=root";
      echo "AUTHORIZED_KEYS=$(cat ./secret/id_rsa.pub)"; } >> ./secret/node.env
else
    INFO "No need to generate key pair"
fi

# Make sure folders referenced in control Dockerfile exist and don't contain leftover files
rm -rf ./control/tiup-cluster
mkdir -p ./control/tiup-cluster/tiup-cluster

if [ "${INIT_ONLY}" -eq 1 ]; then
    exit 0
fi

if [ "${SUBNET##*/}" -ne 24 ]; then
    ERROR "Only subnet mask of 24 bits are currently supported"
    exit 1
fi

if [ "$NODES" -gt "64" ]; then
    ERROR "At most 64 nodes is supported"
    exit 1
fi

exists python ||
    { ERROR "Please install python (https://www.python.org/downloads/)";
      exit 1; }
exists docker ||
    { ERROR "Please install docker (https://docs.docker.com/engine/installation/)";
      exit 1; }

exists pip ||
    { ERROR "Please install pip (https://docs.docker.com/engine/installation/)";
      exit 1; }
pip3 install -U jinja2

exist_network=$(docker network ls | awk '{if($2 == "tiops") print $1}')
if [[ "$exist_network" == "" ]]; then
    docker network create --gateway "${SUBNET%.*}.1" --subnet "${SUBNET}" tiops
else
    echo "Skip create tiup-cluster network"
    SUBNET=$(docker network inspect -f "{{range .IPAM.Config}}{{.Subnet}}{{end}}" tiops)
fi

if [[ "${SUBNET##*/}" -ne 24 ]]; then
    ERROR "Only subnet mask of 24 bits are currently supported"
    exit 1
fi
ipprefix=${SUBNET%.*}

ssh_proxy="False"
proxy_prefix=""
if [[ "${INCLUDE_PROXY_NODES}" -eq 1 ]]; then
    ssh_proxy="True"

    exist_network=$(docker network ls | awk '{if($2 == "tiproxy") print $1}')
    if [[ "$exist_network" == "" ]]; then
        docker network create --gateway "${PROXY_SUBNET%.*}.1" --subnet "${PROXY_SUBNET}" tiproxy
    else
        echo "Skip create tiup-cluster proxy network"
        SUBNET=$(docker network inspect -f "{{range .IPAM.Config}}{{.Subnet}}{{end}}" tiproxy)
    fi
    if [[ "${PROXY_SUBNET##*/}" -ne 24 ]]; then
        ERROR "Only proxy-subnet mask of 24 bits are currently supported"
        exit 1
    fi
    proxy_prefix=${PROXY_SUBNET%.*}
fi

python -c "from jinja2 import Template; print(Template(open('docker-compose.yml.tpl').read()).render(nodes=$NODES, ipprefix='$ipprefix', ssh_proxy=$ssh_proxy, proxy_prefix='$proxy_prefix'))" > docker-compose.yml
sed "s/__IPPREFIX__/$ipprefix/g" docker-compose.dm.yml.tpl > docker-compose.dm.yml
sed -i '/TIUP_TEST_IP_PREFIX/d' ./secret/control.env
echo "TIUP_TEST_IP_PREFIX=$ipprefix" >> ./secret/control.env

INFO "Running \`docker-compose build\`"
cp -a ${TIUP_CLUSTER_ROOT}/* ./control/ || true
docker compose -f docker-compose.yml ${COMPOSE} build

INFO "Running \`docker-compose up\`"
if [ "${RUN_AS_DAEMON}" -eq 1 ]; then
    # shellcheck disable=SC2086
    docker compose -f docker-compose.yml ${COMPOSE} up -d
    INFO "All containers started, run \`docker ps\` to view"
else
    INFO "Please run \`docker exec -it tiup-cluster-control bash\` in another terminal to proceed"
    # shellcheck disable=SC2086
    docker compose -f docker-compose.yml ${COMPOSE} up
fi

popd
