#!/bin/zsh -ex -o pipefail -o err_return

# Ensure we're running at the base of the repo.
orig_dir=$(pwd)
cd "$(dirname $0)/../"

regions=(us-west-2 us-east-1)
accounts=()

function die {
    echo "$@" >&2
    exit 1
}

# Call this to read any stray input before prompting for a question.
function consume_stray_input {
    while read -t foo
    do
        true
    done
}

function get_profile_region {
    export SETUP_GITHUB=0
    consume_stray_input
    [[ -z "$PRIMARY_ACCOUNT" ]] && read "?Prod account alias: " PRIMARY_ACCOUNT
    consume_stray_input
    [[ -z "$SECONDARY_ACCOUNT" ]] && read "?Staging account alias: " SECONDARY_ACCOUNT
    consume_stray_input
    [[ -z "$TEAM_EMAIL" ]] && read "?Team email: " TEAM_EMAIL

    export PRIMARY_ACCOUNT
    export SECONDARY_ACCOUNT
    export TEAM_EMAIL
    accounts=($SECONDARY_ACCOUNT $PRIMARY_ACCOUNT)
}

function this_account_region {
    consume_stray_input
    if read -q "?Set up $1/$2 (y/N)? "
    then
        export AWS_PROFILE=$1
        export AWS_DEFAULT_REGION=$2
    else
        return 1
    fi
}

function clone_github_import {
    dir=$(mktemp -d)
    git clone git@git-aws.internal.justin.tv:vod/github-import "$dir"
    export GITHUB_IMPORT="$dir"
}

function TRAPEXIT {
    [[ -n "$GITHUB_IMPORT" && -d "$GITHUB_IMPORT" ]] && rm -ri "$GITHUB_IMPORT"
}

function import_github {
    if [[ "$AWS_DEFAULT_REGION" != "${regions[1]}" ]]
    then
        return
    fi
    if aws cloudformation describe-stacks --stack-name github-import &>/dev/null
    then
        SETUP_GITHUB=n
    else
        SETUP_GITHUB=y
    fi

    consume_stray_input
    read -q "?Subscribe this repo to github mirroring (y/N)? " SUBSCRIBE_GITHUB || true

    if [[ $SETUP_GITHUB == 'n' && $SUBSCRIBE_GITHUB == 'n' ]]
    then
        return
    fi

    [[ -z "${GITHUB_IMPORT}" ]] && clone_github_import
    pushd -q "$GITHUB_IMPORT"
    trap 'popd -q' EXIT

    if [[ "${SETUP_GITHUB}" == 'y' ]]
    then
        zsh -exo pipefail ./build.sh
    fi

    if [[ $SUBSCRIBE_GITHUB == 'y' ]]
    then
        # TODO: This is a hack :'(
        # remove once https://git-aws.internal.justin.tv/vod/github-import/pull/3 is merged
        sed -i.bak 's/$(aws configure get region)/'$AWS_DEFAULT_REGION'/g' ./subscribe.sh
        zsh -exo pipefail ./subscribe.sh foundation/aid
    fi
}

function create_networking_stack {
    if aws cloudformation describe-stacks --stack-name base-networking-cf &>/dev/null
    then
        return
    fi

    echo "Creating networking stack"
    if [[ ! -f "networking/$AWS_PROFILE/$AWS_DEFAULT_REGION/constants.json" || ! -f "networking/$AWS_PROFILE/$AWS_DEFAULT_REGION/constants.cli.json" ]]
    then
        die "please create networking/$AWS_PROFILE/$AWS_DEFAULT_REGION/constants.json and networking/$AWS_PROFILE/$AWS_DEFAULT_REGION/constants.json.cli and fill them with the parameters for networking/templates/constants_stack.yaml"
    fi
    aws cloudformation create-stack \
        --stack-name=base-networking-cf \
        --template-body file://networking/templates/constants_stack.yaml \
        --parameters "file://networking/$AWS_PROFILE/$AWS_DEFAULT_REGION/constants.cli.json" \
        --capabilities CAPABILITY_IAM
    aws cloudformation wait stack-create-complete --stack-name=base-networking-cf
}

function get_account_id {
    env AWS_PROFILE=$1 aws sts get-caller-identity | jq -r .Account
}

function create_base_pipeline_stack {
    if aws cloudformation describe-stacks --stack-name base-pipeline &>/dev/null
    then
        return
    fi

    if [[ "$AWS_PROFILE" != "$PRIMARY_ACCOUNT" ]]
    then
        primary_account="$(get_account_id $PRIMARY_ACCOUNT)"
        extra_params="--parameters=ParameterKey=AccountId,ParameterValue=$primary_account"
    fi
    aws cloudformation create-stack \
        --stack-name=base-pipeline \
        --capabilities CAPABILITY_NAMED_IAM \
        --template-body file://base-pipeline.yaml ${extra_params}
    aws cloudformation wait stack-create-complete --stack-name base-pipeline
}

function create_base_pipeline_lambdas_stack {
    if [[ $AWS_DEFAULT_REGION != ${regions[1]} ]] || aws cloudformation describe-stacks --stack-name base-pipeline-lambdas &>/dev/null
    then
        return
    fi

    bucket=$(aws cloudformation list-exports --query 'Exports[?Name==`LambdaBucket`]' | jq -r '.[0].Value')
    [[ -z "$bucket" ]] && die "LambdaBucket not found in cloudformation exports"
    aws cloudformation package \
        --template-file base-pipeline-lambdas.yaml \
        --s3-bucket=${bucket} \
        --output-template-file packaged-lambdas.yaml
    aws cloudformation deploy \
        --template-file packaged-lambdas.yaml \
        --stack-name base-pipeline-lambdas \
        --capabilities CAPABILITY_NAMED_IAM
}

function create_base_pipeline_pipeline_stack {
    if aws cloudformation describe-stacks --stack-name base-pipeline-pipeline &>/dev/null
    then
        return
    fi

    local stack_type
    if [[ "$AWS_DEFAULT_REGION" == "${regions[1]}" ]]
    then
        if [[ "$AWS_PROFILE" == "$PRIMARY_ACCOUNT" ]]
        then
            stack_type="primary"
        else
            stack_type="dev"
        fi
    else
        stack_type="secondary"
    fi

    params="$(${stack_type}_pipeline_parameters)"
    echo "$params" | jq '{Parameters: [.[] | {key: .ParameterKey, value: .ParameterValue}] | from_entries}' > pipeline-configs/$stack_type-$(get_account_id $AWS_PROFILE)-$AWS_DEFAULT_REGION.json

    aws cloudformation create-stack \
        --stack-name=base-pipeline-pipeline \
        --capabilities CAPABILITY_NAMED_IAM \
        --template-body file://pipeline/$stack_type.yaml \
        --parameters "$params"
    aws cloudformation wait stack-create-complete --stack-name base-pipeline-pipeline
}

function primary_pipeline_parameters {
    local p="$(core_pipeline_parameters primary)"
    p="$p, {\"ParameterKey\":\"StagingAccountId\",\"ParameterValue\":\"$(get_account_id $SECONDARY_ACCOUNT)\"}"
    local role=$(env AWS_PROFILE=$SECONDARY_ACCOUNT aws cloudformation list-exports --query 'Exports[?Name==`LambdaRole`]' | jq -r '.[0].Value')
    [[ -n "$role" ]] || die "Couldn't find LambdaRole in $SECONDARY_ACCOUNT"
    p="$p, {\"ParameterKey\":\"StagingAccountRole\",\"ParameterValue\":\"$role\"}"
    echo "[$p]"
}

function dev_pipeline_parameters {
    local p="$(core_pipeline_parameters dev)"
    p="$p, {\"ParameterKey\":\"PrimaryAccountId\",\"ParameterValue\":\"$(get_account_id $PRIMARY_ACCOUNT)\"}"
    echo "[$p]"
}

function secondary_pipeline_parameters {
    local p="$(core_pipeline_parameters secondary)"
    echo "[$p]"
}

function core_pipeline_parameters {
    local p="{\"ParameterKey\":\"PipelineType\",\"ParameterValue\":\"$1\"}"
    p="$p, {\"ParameterKey\":\"AccountAlias\",\"ParameterValue\":\"$AWS_PROFILE\"}"
    p="$p, {\"ParameterKey\":\"Email\",\"ParameterValue\":\"$TEAM_EMAIL\"}"
    echo "$p"
}

function main {
    get_profile_region

    echo "We're going to run through this setup once per account/region. Ctrl-c when you're done." >&2
    echo "Accounts:\n  prod: $PRIMARY_ACCOUNT\n  staging: $SECONDARY_ACCOUNT" >&2
    echo "Regions (first is primary): $regions" >&2

    for account in $accounts
    do
        for region in $regions
        do
            if this_account_region $account $region
            then
                import_github
                create_networking_stack
                create_base_pipeline_stack
                create_base_pipeline_lambdas_stack
                create_base_pipeline_pipeline_stack
            fi
        done
    done
}

main

