#! /usr/bin/env bash
# abort on nonzero exitstatus
set -o errexit
# abort on unbound variable
set -o nounset
# don't hide errors within pipes
set -o pipefail

get_app_url() {
    heroku info -j | jq '.app.web_url'
}

get_apps() {
    curl -s --location --request GET "${1}/api/v1/apps" \
        --header "Accept: application/json" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" >apps.json

    jq '.[0]' apps.json >app1.json
    jq '.[1]' apps.json >app2.json
}

add_redirect_url() {
    REDIRECT_URL="${1//\"/}login/oauth2/code/oidc"
    jq '.settings.oauthClient.redirect_uris += ["'"${REDIRECT_URL}"'"]' app1.json >app1-mod.json
    jq '.settings.oauthClient.redirect_uris += ["'"${REDIRECT_URL}"'"]' app2.json >app2-mod.json

    jq '.settings.oauthClient.post_logout_redirect_uris += ["'"${1//\"/}"'"]' app1-mod.json >app1.json
    jq '.settings.oauthClient.post_logout_redirect_uris += ["'"${1//\"/}"'"]' app2-mod.json >app2.json
}

update_apps() {
    data=$(jq '.' app1.json)
    id=$(jq '.id' app1.json)

    curl -s --location --request PUT "${1}/api/v1/apps/${id//\"/}" \
        --header "Accept: application/json" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" \
        --data-raw "${data}"

    data=$(jq '.' app2.json)
    id=$(jq '.id' app2.json)

    curl -s --location --request PUT "${1}/api/v1/apps/${id//\"/}" \
        --header "Accept: application/json" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" \
        --data-raw "${data}"
}

add_groups() {
    curl -s --location --request POST "${1}/api/v1/groups" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" \
        --data-raw '{"profile":
            {
                "name": "ROLE_ADMIN",
                "description": "JHipster Admin Role"
            }
        }'

    curl -s --location --request POST "${1}/api/v1/groups" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" \
        --data-raw '{"profile":
            {
                "name": "ROLE_USER",
                "description": "JHipster User Role"
            }
        }'
}

add_admin_to_group() {
    ADMIN_EMAIL=$(heroku config:get OKTA_ADMIN_EMAIL)

    GROUP_ID=$(curl -s --location --request GET "${1}/api/v1/groups?q=ROLE_ADMIN" \
        --header "Authorization: SSWS ${2}" | jq '.[0].id')

    USER_ID=$(curl -s --location --request GET "${1}/api/v1/users?q=${ADMIN_EMAIL}" \
        --header "Accept: application/json" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" | jq '.[0].id')

    curl -s --location --request PUT "${1}/api/v1/groups/${GROUP_ID//\"/}/users/${USER_ID//\"/}" \
        --header "Authorization: SSWS ${2}" \
        --data-raw ''
}

add_groups_claim() {
    curl -s --location --request POST "${1}/api/v1/authorizationServers/default/claims" \
        --header "Accept: application/json" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" \
        --data-raw '{
        "name": "groups",
        "status": "ACTIVE",
        "claimType": "IDENTITY",
        "valueType": "GROUPS",
        "value": ".*",
        "conditions": {
            "scopes": []
        },
        "system": false,
        "alwaysIncludeInToken": true,
        "group_filter_type": "REGEX"
    }'
}

add_admin_user() {

    GROUP_ID=$(curl -s --location --request GET "${1}/api/v1/groups?q=ROLE_ADMIN" \
        --header "Authorization: SSWS ${2}" | jq '.[0].id')

    # Create user with provided initial password
    USER_ID=$(curl -s --location --request POST "${1}/api/v1/users?activate=true" \
        --header "Accept: application/json" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" \
        --data-raw '
        {
          "profile": {
            "firstName": "JHipster",
            "lastName": "Admin",
            "email": "<%= oktaAdminLogin  %>",
            "login": "<%= oktaAdminLogin %>"
          },
          "credentials": {
            "password" : { "value": "<%= oktaAdminPassword %>" }
          }
        }' | jq '.id')

    curl -s --location --request PUT "${1}/api/v1/groups/${GROUP_ID//\"/}/users/${USER_ID//\"/}" \
        --header "Authorization: SSWS ${2}" \
        --data-raw ''

    # directly expire the password such that the user is forced to select a new password
    curl -s --location --request POST "${1}/api/v1/users/${USER_ID//\"/}/lifecycle/expire_password" \
        --header "Content-Type: application/json" \
        --header "Accept: application/json" \
        --header "Authorization: SSWS ${2}" \
        --data-raw ''
}

already_done() {
    LENGTH=$(curl -s --location --request GET "${1}/api/v1/users?q=<%= oktaAdminLogin  %>" \
        --header "Accept: application/json" \
        --header "Content-Type: application/json" \
        --header "Authorization: SSWS ${2}" | jq '. | length')
    
    if [ $LENGTH -gt 0 ]
    then
        echo "true"
    else
        echo "false"
    fi
}

check_required_dependencies() {
    if hash curl 2>/dev/null;
    then
        echo -e "\U2714 cURL is available."
    else
        echo "\U1F6D1cURL is not available but required. See https://curl.haxx.se/download.html for installation guidance."
        return 0;
    fi

    if hash jq 2>/dev/null;
    then
        echo -e "\U2611 jq is available.️"
    else
        echo -e "\U1F6D1jq is not available but required. See https://stedolan.github.io/jq/download/ for installation guidance."
        return 0;
    fi
}

main() {
    check_required_dependencies

    OKTA_URL=$(heroku config:get OKTA_CLIENT_ORGURL)
    OKTA_TOKEN=$(heroku config:get OKTA_CLIENT_TOKEN)

    APP_URL=$(get_app_url)

    DONE=$(already_done ${OKTA_URL} ${OKTA_TOKEN})

    if  [ ${DONE} == "true" ]
    then
        echo "User already created, doing nothing."
        return 0
    fi

    # First add the correct redirect url to each application
    get_apps "${OKTA_URL}" "${OKTA_TOKEN}"
    add_redirect_url "${APP_URL}"
    update_apps "${OKTA_URL}" "${OKTA_TOKEN}"

    # Create ROLE_ADMIN and ROLE_USER groups
    add_groups "${OKTA_URL}" "${OKTA_TOKEN}"

    # Add the automatically provisioned HEROKU ADMIN to the ROLE_ADMIN group
    add_admin_to_group "${OKTA_URL}" "${OKTA_TOKEN}"

    # Add the groups claim, see https://www.jhipster.tech/security/#okta
    add_groups_claim "${OKTA_URL}" "${OKTA_TOKEN}"

    add_admin_user "${OKTA_URL}" "${OKTA_TOKEN}"

    # Delete all temporary files created during this script
    rm apps.json
    rm app1.json
    rm app2.json
    rm app1-mod.json
    rm app2-mod.json
}

main
