#!/bin/bash

set -eu -o pipefail

assertNotEmpty() {
    : "${!1:? "$1 is not set."}"
}

readonly SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
readonly SOURCE_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")"/.. && pwd)"
export JSON="${SOURCE_DIR}/node_modules/.bin/json"

INSTANCE_TYPE="t2.micro"
BLOCK_DEVICE="DeviceName=/dev/sda1,Ebs={VolumeSize=20,DeleteOnTermination=true,VolumeType=gp2}"
SSH_KEY_NAME="id_rsa_yellowtent"

revision=$(git rev-parse HEAD)
ami_name=""
server_id=""
server_ip=""
destroy_server="yes"
deploy_env="prod"
image_id=""

args=$(getopt -o "" -l "revision:,name:,no-destroy,env:,region:" -n "$0" -- "$@")
eval set -- "${args}"

while true; do
    case "$1" in
    --env) deploy_env="$2"; shift 2;;
    --revision) revision="$2"; shift 2;;
    --name) ami_name="$2"; shift 2;;
    --no-destroy) destroy_server="no"; shift 2;;
    --region)
        case "$2" in
        "us-east-1")
            image_id="ami-6edd3078"
            security_group="sg-a5e17fd9"
            subnet_id="subnet-b8fbc0f1"
            ;;
        "eu-central-1")
            image_id="ami-5aee2235"
            security_group="sg-19f5a770" # everything open on eu-central-1
            subnet_id=""
            ;;
        *)
            echo "Unknown aws region $2"
            exit 1
            ;;
        esac
        export AWS_DEFAULT_REGION="$2"    # used by the aws cli tool
        shift 2
        ;;
    --) break;;
    *) echo "Unknown option $1"; exit 1;;
    esac
done

# TODO fix this
export AWS_ACCESS_KEY_ID="${AWS_ACCESS_KEY}"
export AWS_SECRET_ACCESS_KEY="${AWS_ACCESS_SECRET}"

readonly ssh_keys="${HOME}/.ssh/id_rsa_yellowtent"
readonly SSH="ssh -o IdentitiesOnly=yes -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no -i ${ssh_keys}"

if [[ ! -f "${ssh_keys}" ]]; then
    echo "caas ssh key is missing at ${ssh_keys} (pick it up from secrets repo)"
    exit 1
fi

if [[ -z "${image_id}" ]]; then
    echo "--region is required (us-east-1 or eu-central-1)"
    exit 1
fi

function get_pretty_revision() {
    local git_rev="$1"
    local sha1=$(git rev-parse --short "${git_rev}" 2>/dev/null)

    echo "${sha1}"
}

function wait_for_ssh() {
    echo "=> Waiting for ssh connection"
    while true; do
        echo -n "."

        if $SSH ubuntu@${server_ip} echo "hello"; then
            echo ""
            break
        fi

        sleep 5
    done
}

now=$(date "+%Y-%m-%d-%H%M%S")
pretty_revision=$(get_pretty_revision "${revision}")

if [[ -z "${ami_name}" ]]; then
    ami_name="box-${deploy_env}-${pretty_revision}-${now}"
fi

echo "=> Create EC2 instance"
id=$(aws ec2 run-instances --image-id "${image_id}" --instance-type "${INSTANCE_TYPE}" --security-group-ids "${security_group}" --block-device-mappings "${BLOCK_DEVICE}" --key-name "${SSH_KEY_NAME}" --subnet-id "${subnet_id}" --associate-public-ip-address \
    | $JSON Instances \
    | $JSON 0.InstanceId)

[[ -z "$id" ]] && exit 1
echo "Instance created  ID $id"

echo "=> Waiting for instance to get a public IP"
while true; do
    server_ip=$(aws ec2 describe-instances --instance-ids ${id} \
        | $JSON Reservations.0.Instances \
        | $JSON 0.PublicIpAddress)

    if [[ ! -z "${server_ip}" ]]; then
        echo ""
        break
    fi

    echo -n "."
    sleep 1
done

echo "Got public IP ${server_ip}"

wait_for_ssh

echo "=> Fetching cloudron-setup"
while true; do

    if $SSH ubuntu@${server_ip} wget "https://cloudron.io/cloudron-setup" -O "cloudron-setup"; then
        echo ""
        break
    fi

    echo -n "."
    sleep 5
done

echo "=> Running cloudron-setup"
$SSH ubuntu@${server_ip} sudo /bin/bash "cloudron-setup" --env "${deploy_env}" --provider "ami" --skip-reboot

wait_for_ssh

echo "=> Removing ssh key"
$SSH ubuntu@${server_ip} sudo rm /home/ubuntu/.ssh/authorized_keys /root/.ssh/authorized_keys

echo "=> Creating AMI"
image_id=$(aws ec2 create-image --instance-id "${id}" --name "${ami_name}" | $JSON ImageId)
[[ -z "$id" ]] && exit 1
echo "Creating AMI with Id ${image_id}"

echo "=> Waiting for AMI to be created"
while true; do
    state=$(aws ec2 describe-images --image-ids ${image_id} \
        | $JSON Images \
        | $JSON 0.State)

    if [[ "${state}" == "available" ]]; then
        echo ""
        break
    fi

    echo -n "."
    sleep 5
done

if [[ "${destroy_server}" == "yes" ]]; then
    echo "=> Deleting EC2 instance"

    while true; do
        state=$(aws ec2 terminate-instances --instance-id "${id}" \
            | $JSON TerminatingInstances \
            | $JSON 0.CurrentState.Name)

        if [[ "${state}" == "shutting-down" ]]; then
            echo ""
            break
        fi

        echo -n "."
        sleep 5
    done
fi

echo ""
echo "Done."
echo ""
echo "New AMI is: ${image_id}"
echo ""
