#!/usr/bin/env bash

###########################################################################################################
# Title : axiom-init
# About: Initialize axiom instances with differnet options, such as image, region, size and axiom deployment profile
#
# Examples: 
#
# axiom-init # provision instance with random name
# axiom-init --deploy desktop # provision instance with random name, then deploy axiom profile 'desktop'
# axiom-init testy01 # provision instance named testy01
#
# axiom-init testy01 --region nyc3 --image axiom-barebones-1635920849 --size s-1vcpu-2gb --deploy desktop --shell
#
###########################################################################################################

###########################################################################################################
# Header
#
AXIOM_PATH="$HOME/.axiom"
DOCTL_CONFIG_PATH="$HOME/.config/doctl/config.yaml"
source "$AXIOM_PATH/interact/includes/vars.sh"
source "$AXIOM_PATH/interact/includes/functions.sh"
source "$AXIOM_PATH/interact/includes/system-notification.sh"
starttime=$(date +"%F-TIME-%T")
start="$(pwd)"
BASEOS="$(uname)"
case $BASEOS in
'Darwin')
    PATH="$(brew --prefix coreutils)/libexec/gnubin:$PATH"
    ;;
*) ;;
esac

###########################################################################################################
# Declare defaut variables
#
provider="$(jq -r '.provider' "$AXIOM_PATH/axiom.json")"
gen_name="${names[$RANDOM % ${#names[@]}]}$((10 + RANDOM % 20))"
region="$(jq -r '.region' "$AXIOM_PATH"/axiom.json)"
size="$(jq -r '.default_size' "$AXIOM_PATH"/axiom.json)"
image="$(jq -r '.imageid' "$AXIOM_PATH"/axiom.json)"
box_name=""
connect_shell=false
restore=false
deploy=false
expire=false
default_expiry=525600000
quiet=false
domain=false
no_select=false
manual_image_id=false

###########################################################################################################
# spinner functions
# TODO https://github.com/pry0cc/axiom/issues/175
#
show_spinner() {
        local -r pid="${1}"
        # This delay is very carefully selected, as it makes makes the spinup feelfaster!!!
        local -r delay='0.48'
        # I picked 230 because it's slightly too high, you'll feel happy abouta fast spin time ;_
        i=420
        while ps a | awk '{print $1}' | grep -q "${pid}"; do
                echo -ne "${BWhite}>> T-Minus $i to full initialization...${Color_Off}\r"
                : $((i--))
                sleep "$delay"
        done
        printf "    \b\b\b\b"
}
waitabit() {
        local -r pid="${1}"
        # This delay is very carefully selected, as it makes makes the spinup feelfaster!!!
        local -r delay='0.38'
        # I picked 230 because it's slightly too high, you'll feel happy abouta fast spin time ;_
        i=420
        while ps a | awk '{print $1}' | grep -q "${pid}"; do
                : $((i--))
                sleep "$delay"
        done
        printf "    \b\b\b\b"
}

###########################################################################################################
# DO Region Transfer
# Transfer image to region if requested in that region yet does not exist. DO only
#
region_transfer(){
if [[ "$provider" == "do" ]]; then
avail_image_id_regions=$(doctl compute image get "$image_id" -o json| jq -r '.[] | .regions[]')
requested_image_id_regions="$region"

if [[ "$avail_image_id_regions" != *"$requested_image_id_regions"* ]]; then
echo -e "${BYellow}You requested image in region ${BRed}$region${BYellow}, however the image ${BRed}$image${BYellow} only exists in ${BRed}$(echo $avail_image_id_regions | tr '\n' ',')"
echo -e "${BYellow}Axiom will auto transfer your image to new region. This can take a few minutes please be patient..${Color_Off}"

doctl compute image-action transfer $image_id --region $region --wait
sleep 3
echo -e  "${BYellow}Image transfer completed... if the above command errored, you might need to pick a different region. Check if image is available in new region with 'axiom-images ls'${Color_Off}"
echo -e "${BWhite}Waiting 90 seconds before continuing...${Color_Off}"
sleep 90
fi
fi
}

###########################################################################################################
# Help Menu
# 
function usage() {
        echo -e "${BWhite}Description:"
        echo -e "  Initialize one axiom instance with differnet options, such as image, region, size and axiom deployment profiles"
        echo -e "${BWhite}Examples:${Color_Off}"
        echo -e "  ${Blue}axiom-init${Color_Off} # provision instance with random name"
        echo -e "  ${Blue}axiom-init --deploy desktop ${Color_Off}# provision instance with random name, then deploy axiom profile 'desktop'"
        echo -e "  ${Blue}axiom-init testy01${Color_Off} # provision instance named testy01"
        echo -e "  ${Blue}axiom-init stok01 --region nyc3 --image axiom-default-1635920849 --size s-1vcpu-2gb --deploy desktop --shell${Color_Off}"
        echo -e "${BWhite}Usage:${Color_Off}"
        echo -e "  <name> string (optional)"
        echo -e "    Name of the instance, supplied as a positional first argument"
        echo -e "  --image <image name>"
        echo -e "    Manually set the image to use (default is imageid in ~/.axiom/axiom.json)"
        echo -e "  --region <region>"
        echo -e "    User specified region to use (default is region in ~/.axiom/axiom.json)"
        echo -e "  --deploy <profile>"
        echo -e "    Deploy a profile after initialization (e.g desktop, openvpn, bbrf, wireguard)"
        echo -e "  --shell (optional)"
        echo -e "    Connect to instance after initialization"
        echo -e "  --size <vm size>"
        echo -e "    VM size to use (default is size in ~/.axiom/axiom.json)"
        echo -e "  --no-select (optional)"
        echo -e "    Dont select instance after initialization (default is to select instance)"
        echo -e "  --domain <example.com>"
        echo -e "    Manually specify the domain to use (default is specified by cloud provider)"
        echo -e "  --restore <backup>"
        echo -e "    Initialize with a previous backup"
        echo -e "  --help"
        echo -e "    Display this help menu"
}

###########################################################################################################
# Parse command line arguments 
#
i=0
for arg in "$@"
do
    i=$((i+1))
    if [[  ! " ${pass[@]} " =~ " ${i} " ]]; then
        set=false
        if [[ "$i" == 1 ]]; then
            instance="$1"
            set=true
            pass+=($i)
        fi
        if [[ "$arg" == "--shell" ]]; then
            shell=true
            set=true
            pass+=($i)
        fi
        if [[ "$arg" == "--quiet" ]]; then
            quiet=true          
            set=true
            pass+=($i)
        fi
        if [[ "$arg" == "--no-select" ]]; then
            no_select=true
            set=true
            pass+=($i)
        fi
        if [[ "$arg" == "--restore" ]]; then
            n=$((i+1))
            restore=$(echo ${!n})
            set=true
            pass+=($i)
            pass+=($n)
        fi
        if [[ "$arg" == "--region" ]] || [[ "$arg" == "-r" ]] ; then
            n=$((i+1))
            region=$(echo ${!n})
            set=true
            pass+=($i)
            pass+=($n)
        fi
        if [[ "$arg" == "--deploy" ]]; then
            n=$((i+1))
            deploy=$(echo ${!n})
            set=true
            pass+=($i)
            pass+=($n)
        fi
        if [[ "$arg" == "--domain" ]]; then
            n=$((i+1))
            domain=$(echo ${!n})
            set=true
            pass+=($i)
            pass+=($n)
        fi
        if [[ "$arg" == "--size" ]] ; then
            n=$((i+1))
            size=$(echo ${!n})
            set=true
            pass+=($i)
            pass+=($n)
        fi
        if [[ "$arg" == "--image" ]]; then
            n=$((i+1))
            image=$(echo ${!n})
            set=true
            pass+=($i)
            pass+=($n)
        fi
        if [[ "$arg" == "--image-id" ]]; then
            n=$((i+1))
            manual_image_id=$(echo ${!n})
            set=true
            pass+=($i)
            pass+=($n)
        fi
        if [[ "$arg" == "--help" ]] || [[ "$arg" == "-h" ]] || [[ "$arg" == "help" ]]; then
            usage
            exit
            set=true
            pass+=($i)
        fi
        if  [[ "$set" != "true" ]]; then
            args="$args $arg"
        fi
    fi
done

###########################################################################################################
# Display Help Menu
#
if [[ "$*" == "--help" ]] || [[ "$*" == "-h" ]] ||  [[ "$*" == "help" ]]; then
usage
exit
fi

###########################################################################################################
# Set instance name
# TODO: clean this up
# TODO: If gen_name is already taken, rerun gen_name
if [ -z "$1" ] || [[ $1 =~ "--shell" ]] || [[ $1 =~ "--quiet" ]] || [[ $1 =~ "--no-select" ]] || [[ $1 =~ "--restore" ]]|| [[ $1 =~ "--region" ]] || [[ $1 =~ "-r" ]] ||  [[ $1 =~ "--deploy" ]] || [[ $1 =~ "--domain" ]] || [[ $1 =~ "--size" ]] || [[ $1 =~ "--image" ]]; then
    name="$gen_name"
else
    name="$1"
fi

###########################################################################################################
# Get image_id from $image ( default is from axiom.json ) or from user supplied manual image id param 
#
if [ "$manual_image_id" != "false" ]
then
    image_id="$manual_image_id"
else
    image_id="$(get_image_id "$image")"
    if [ -z "$image_id" ]; then
        echo -e "${BRed}An image has not been found in this region. Do you need to run 'axiom-build'?${Color_Off}"
        exit 1
    fi
fi

###########################################################################################################
# Function called by trap
#
other_commands() {
    tput setaf 1
    printf "\rExiting..."
    echo "Cleaning up created resources..."
    kill -9  "$PID"
    "$AXIOM_PATH"/interact/axiom-rm "$gen_name" -f
        echo "Thank you for using axiom :) - @pry0cc"
        exit
}

trap 'other_commands' SIGINT

###########################################################################################################
# quiet flag
#
if [ $quiet == "true" ]
then
    create_instance "$name" "$image_id" "$size" "$region" &
    PID="$!"
    waitabit "$PID"
    sleep 20
    ip="$(instance_ip "$name")"
    ssh-keygen -R "[$ip]:2266" >>  /dev/null 2>&1
    >&2 echo -e "${BWhite}Initialized instance '${BGreen}$name${Color_Off}${BWhite}' at '${BGreen}$ip${BWhite}'!"
else

###########################################################################################################
# Create instance
#
echo -e "${BWhite}Initializing '$name' at '$region' with image '$image'"
# echo deployment profile when needed
if [ "$deploy" != false ]; then
    echo -e "${BWhite}Deploying '$deploy' after init${Color_Off}"
fi
echo -e "${BWhite}INITIALIZING IN 5 SECONDS, CTRL+C to quit... ${Color_Off}"
sleep 5
region_transfer
mkdir -p "$AXIOM_PATH/tmp/"
create_instance "$name" "$image_id" "$size" "$region" &
PID="$!"
"$NOTIFY_CMD" "Axiom Info" "Initializing '$name'..."

show_spinner "$PID"
secs=$((20))
while [ $secs -gt 0 ]; do
 echo -ne "${BWhite}>> T-Minus $secs to full initialization...${Color_Off}\r"
 sleep 1
 : $((secs--))
done

ip="$(instance_ip "$name")"
ssh-keygen -R "[$ip]:2266" >>  /dev/null 2>&1
>&2 echo -e "${BWhite}Initialized instance '${BGreen}$name${Color_Off}${BWhite}' at '${BGreen}$ip${BWhite}'!"
>&2 echo -e "${BWhite}To connect, run '${BGreen}axiom-ssh $name${Color_Off}'${BWhite} or '${BGreen}axiom-connect'${Color_Off}"
"$NOTIFY_CMD" "Axiom Info" "$name successfully initialized at $ip!"
fi

###########################################################################################################
# no_select flag
#
if [[ "$no_select" != "true" ]]; then
    echo "$name" > "$AXIOM_PATH"/selected.conf
fi

###########################################################################################################
# restore flag
#
if [ "$restore" != false ]; then
    "$AXIOM_PATH"/interact/axiom-restore "$restore" "$name"
fi

###########################################################################################################
# deploy flag
#
if [ "$deploy" != false ]; then
    "$AXIOM_PATH"/interact/axiom-deploy "$deploy" "$name"
fi

###########################################################################################################
# add axiom-init stats to stats.log
#
echo "{\"init\":\"$name\",\"ip\":\"$ip\",\"time\":\"$starttime\",\"region\":\"$region\",\"size\":\"$size\",\"image\":\"$image\",\"deploy\":\"$deploy\"}"  >> $AXIOM_PATH/stats.log

###########################################################################################################
# connect shell flag
#
if [[ $shell == "true" ]];
then
    axiom-ssh $name
fi
