#!/bin/bash
set -e
[[ $TRACE ]] && set -x
set -u

# TODO check prerequires
# 1. asg, jq, curl
# 2. docker registry and qloud OAuth tokens
# 3. asg path

single_component=0
curl_tmp="/tmp/$$-curl"
dump_tmp="/tmp/$$-curl-dump" # HACK subst for $dump var that hits Ubuntu BASH 128K var size limit
prompt_tmp="/tmp/$$-prompt"
env_data_tmp="/tmp/$$-env-data"
countdown_seconds=15
list_max_items=50
terminal_cols=$(tput cols)
source ./ops-deploy-config/$1.conf # TODO check file exists
registry_auth="Authorization: OAuth $(cat ~/.docker.token)"
registry_digest_header="Accept: application/vnd.docker.distribution.manifest.v2+json"
registry_url="https://registry.yandex.net/v2/"

qloud_auth="Authorization: OAuth $(cat ~/.qloud.token)"
qloud_dump_url="https://platform.yandex-team.ru/api/v1/environment/dump/mail"
qloud_target_state=DEPLOYED  # PREPARED DEPLOYED COMMITTED
qloud_upload_url="https://platform.yandex-team.ru/api/v1/environment/upload?targetState=${qloud_target_state}&skipIfNoChange=true"
qloud_web_url="https://platform.yandex-team.ru/projects/mail"
qloud_status_url="https://platform.yandex-team.ru/api/v1/environment/stable/mail"

asg_path="$HOME/asg/asg"

function http_call {
    code=$(curl --write-out %{http_code} --silent --output "$curl_tmp" "$@")
    if [[ "$code" != "200" ]]; then
        echo "HTTP call failed with status $code $@"
        return 1
    fi
}

function http_response {
    cat "$curl_tmp"
}

function friendly_version {
    date=$(echo ${1:1:16} | sed 's/./ /11' | sed 's/./:/14')
    echo "${1:17} $date"
}

function source_repository_tag {
    echo $1 | sed 's/^r/'"$source_repository_tags_prefix"-'/'
}

function countdown {
    text=$1
    secs=$2
    echo
    while [[ $secs -gt 0 ]]; do
        echo -ne "\r$text $secs \033[0K"
        read -s -n 1 -t 1 key && break || true
        if [[ $? != 0 ]]; then
            break
        fi
        : $((secs--))
    done
    echo -ne "\r$text \033[0K"
}

function gen_env_data {
    http_call -H "$qloud_auth" "${qloud_dump_url}.${project}.${env}"
    cp -f "$curl_tmp" "$dump_tmp" # HACK "define" dump variable
    export qloud_info=$(http_response | jq -r '.components[].properties|.repository + " " + .hash' | grep "$registry_path")
    component_versions=$(echo "$qloud_info" | grep "$registry_path")
    if [[ "$single_component" != 0 ]]; then
        component_versions=$(echo "$component_versions" | sed "${single_component}!d")
    fi
    export version_old=$(echo "$component_versions" | awk -F ' |:' '{print $2}')
    export hash_old=$(echo "$component_versions" | awk '{print $2}' )
    export ready_to_deploy=0
    version_count=$(echo "$component_versions" | sort -u | wc -l | awk '{print $1}')
    version_count_only_old=$(echo "$component_versions" | grep -v "$version_new" | sort -u | wc -l | awk '{print $1}')

    if [[ "$version_count" == "1" && "$version_count_only_old" == 0 ]]; then
        export version_output="+ done"

    elif [[ "$version_count_only_old" == "1" ]]; then # both regular release and canary release
        export version_old=$(echo "$component_versions" | grep -v "$version_new" | uniq | awk -F ' |:' '{print $2}')
        export hash_old=$(echo "$component_versions" | grep -v "$version_new" | uniq | awk '{print $2}' )
        export version_output="$(friendly_version $version_old) -> $(friendly_version $version_new)"
        export ready_to_deploy=1

    else
        export version_output="! different versions"

    fi
}

function poll_qloud_status {
    version=$1
    i=0
    sp="/-\|"
    prev_output_sz=0
    while :; do
        http_call "${qloud_status_url}.${project}.${env}/${qloud_version_new}" -H "$qloud_auth"
        output=$(http_response | jq -r '.statusHistory.messages[] | (.time | todate) + "    " + .status')
        output_sz=$(echo "$output" | wc -l)
        if [[ $output_sz != $prev_output_sz ]]; then
            echo -ne "\r\033[0K"
            if [[ $prev_output_sz == 0 ]]; then
                echo "$output"
            else
                echo "$output" | tail -n 1
            fi
            prev_output_sz=$output_sz
        fi
        status=$(http_response | jq -r '.status')
        if [[ $status == "$qloud_target_state" ]]; then
            break;
        fi
        echo -ne "\r${sp:i++%${#sp}:1} \033[0K"
        sleep 1
    done
}

function set_version {
    sed_global=g
    if [[ "$3" != 0 ]]; then
        sed_global=""
    fi
    sed 's/'"$1"'/'"$2"'/'"$sed_global"''
}

case "$2" in
list | ls)
    http_call -H "$registry_auth" "${registry_url}${registry_path}/tags/list"
    http_response | jq -r '.tags[]' | sort
;;

run)
    version_new=$3
    http_call -I -H "$registry_auth" -H "$registry_digest_header" "${registry_url}${registry_path}/manifests/${version_new}"
    hash_new=$(http_response | grep Docker-Content-Digest | awk '{print $2}' | tr -d '\r')
    > $prompt_tmp

    while :; do
        echo
        printf "%0.s-" $(seq 1 $terminal_cols)
        echo
        i_env=1
        for env in ${envs[@]}; do
            gen_env_data
            # source "$env_data_tmp"
            printf "%d %-22s %-60s %s\n" $i_env "$env" "$version_output" "$qloud_web_url/$project/$env"
            i_env=$(( $i_env + 1 ))
        done
        i_env=$(($i_env-1))

        read -p "Select env (1-$i_env): " -n 1 -r
        echo
        echo
        if [[ ! $REPLY =~ ^[1-9]$ ]]; then
            continue
        fi
        env=${envs[$(($REPLY-1))]}

        gen_env_data

        if [[ "$ready_to_deploy" != "1" ]]; then
            echo "Can't deploy environment"
            continue
        fi

        echo "Generating changelog for ${env} $version_old -> $version_new"
        changelog=$($asg_path changelog "$source_code_path" \
            "$(source_repository_tag $version_old)" \
            "$(source_repository_tag $version_new)" | tr '"' "'")
        echo "========================================"
        echo "$changelog"
        echo "========================================"

        countdown "Starting deploy (press Ctrl+C to abort)... " $countdown_seconds

        cat "$dump_tmp" | jq '.comment = "'"$changelog"'"' | tr -d '\n' | \
            set_version "$version_old" "$version_new" $single_component | \
            set_version "$hash_old" "$hash_new" $single_component | \
            http_call  "$qloud_upload_url" -H "$qloud_auth" -H "Content-Type: application/json" -d @- || { http_response; exit 1; }
            qloud_version_new=$(http_response | jq '.version')

        echo "${qloud_web_url}/${project}/${env}?version=${qloud_version_new}"

        poll_qloud_status $qloud_version_new
    done
;;

esac
