#! /bin/bash
#set -x
function usage()
{
    code=${1:-0}
    echo 'create-iotcore-credential.sh [args...]'
    echo ''
    echo 'Create a thing-certificate-policy tuple.'
    echo ''
    echo '-d [suite_id]    (OPTIONAL) device advisor suite id'
    echo '-t [thing_name]  (REQUIRED) the iot thing name'
    echo '-n [policy name] (REQUIRED) the iot policy name'
    echo '-F               (OPTIONAL) Force.  Do not check it objects exist.'
    echo '-f [policy file] (OPTIONAL) when policy does not exist, use this policy file'
    echo '-i [aws|csr]     (OPTIONAL) default:aws'
    echo '-s [csr_file]    (OPTIONAL) when using private pki, use this csr'
    echo '-o [dir]         (OPTIONAL) default: $volatile_dir/$thing_name'
    echo '-s [name]        (OPTIONAL) Add an AWS Secrets Manager item with this info'
    echo '-S               (OPTIONAL) Update secret instead of create'
    echo '-e               (OPTIONAL) export worthwhile variants to file'
    echo ''
    echo '$volatile_dir by default is $(dirname $0)/../../volatile'
    echo ''
    echo 'See also:'
    exit $code
}

FORCE=0
volatile_dir=$(dirname $0)/../../volatile
suite_id=
SECRET_UPDATE=0
while getopts "eFSo:t:n:f:h:s:d:" opt; do
    case ${opt} in
        d)  suite_id=$OPTARG
            ;;
        t)  THING_NAME=$OPTARG
            ;;
        F)  FORCE=1
            ;;
        f)  POLICY_FILE=$OPTARG
            ;;
        n)  POLICY_NAME=$OPTARG
            ;;
        s)  SECRET_NAME=$OPTARG
            ;;
        S)  SECRET_UPDATE=1
            ;;
        o)  volatile_dir=$OPTARG
            ;;
        h)  usage 0
            ;;
    esac
done

region=${region:-us-west-2}
profile=${profile:-default}
std_awscli_args="--output text --region ${region} --profile ${profile}"

if test x"$THING_NAME" == x; then usage 1; fi
if test x"$POLICY_NAME" == x; then usage 1; fi

ACCOUNT_ID=$(aws ${std_awscli_args} sts get-caller-identity --output text --query Account)

function thing_exists {
    _thing_name=$1

    echo "Checking if thing name exists.  This can take a long time if you have a lot of things registered."
    result=$(aws iot list-things ${std_awscli_args} \
        --query "things[?thingName=='$_thing_name'].thingName")

    if test x"$result" == x; then return 1; fi

    return 0
}

function get_thing_arn {
    _thing_name=$1

    echo "Retrieving thing ARN.  This can take a long time if you have a lot of things registered."
    THING_ARN=$(aws iot list-things ${std_awscli_args} \
        --query "policies[?thingName=='$_thing_name'].thingArn")

    if test $? != 0; then return 1; fi

    return 0
    echo stub
}

function create_thing {
    _thing_name=$1

    THING_ARN=$(aws iot create-thing ${std_awscli_args}                                        \
                    --thing-name ${_thing_name}                                         \
                    --query thingArn)

    if test $? != 0; then return 1; fi

    return 0
}

function policy_exists {
    _policy_name=$1
    result=$(aws iot list-policies ${std_awscli_args} \
        --query "policies[?policyName=='$_policy_name'].policyName")

    if test x"$result" == x; then return 1; fi

    return 0
}

function get_policy_arn {
    _policy_name=$1

    POLICY_ARN=$(aws iot list-policies ${std_awscli_args} \
        --query "policies[?policyName=='$_policy_name'].policyArn")

    if test $? != 0; then return 1; fi

    return 0
}

function create_policy {
    sed -e "s/ACCOUNT_ID/${ACCOUNT_ID}/g" -e "s/REGION/${region}/g" ${POLICY_FILE} > /tmp/policy.$$.json
    
    POLICY_ARN=$(aws iot create-policy ${std_awscli_args}                     \
                     --policy-name ${POLICY_NAME}                             \
                     --policy-document file:///tmp/policy.$$.json             \
                     --query policyArn)

    if test $? != 0; then return 1; fi
    
    sleep 3 # Potential for eventual consistency issues here.
    return 0
}

function create_certificate_devmode {
    CERTIFICATE_ARN=$(aws iot create-keys-and-certificate ${std_awscli_args}  \
                          --set-as-active                                     \
                          --certificate-pem-outfile ${certificate_file}       \
                          --public-key-outfile      ${pubkey_file}            \
                          --private-key-outfile     ${privkey_file}           \
                          --query certificateArn)
    CERTIFICATE_ID=$(echo ${CERTIFICATE_ARN} | cut -f2 -d'/')
}

function link_objects {
    aws iot attach-principal-policy ${std_awscli_args}                        \
        --policy-name ${POLICY_NAME}                                          \
        --principal ${CERTIFICATE_ARN}  || return 1

    aws iot attach-thing-principal ${std_awscli_args}                         \
        --thing-name ${THING_NAME}                                            \
        --principal  ${CERTIFICATE_ARN} || return 1

    return 0
}

function create_certificate_csr {
    echo stub
}

function store_secret {
    thing_name=$1
    thing_arn=$2
    certificate_arn=$3
    certificate_file=$4
    privatekey_file=$5
    iotcore_endpoint=$6
    da_endpoint=$(aws iot describe-endpoint \
                      --endpoint-type iot:deviceadvisor \
                      --output text --query endpointAddress)
    da_suite=${suite_id}
    # make key and certificate storable
    certificate=$(base64 --wrap=0 ${certificate_file})
    privatekey=$(base64 --wrap=0 ${privatekey_file})
    secret_name=$SECRET_NAME
    
    cat <<OUT > /tmp/secret_string.json
{ "thing_name" : "${thing_name}",
  "thing_arn" : "${thing_arn}",
  "certificate" : "${certificate}",
  "certificate_arn" : "${certificate_arn}",
  "privatekey" : "${privatekey}",
  "iotcore_endpoint" : "${iotcore_endpoint}",
  "da_endpoint" : "${da_endpoint}",
  "da_suite" : "${da_suite}"
}
OUT

    #    secret_string=$(cat /tmp/secret_string.json)
    if test $SECRET_UPDATE == 0; then
        secret_arn=$(aws secretsmanager create-secret \
                         --secret-string file:///tmp/secret_string.json \
                         --name ${secret_name} \
                         --description "Credentials for Device Advisor" \
                         --output text --query ARN)
    else
        secret_arn=$(aws secretsmanager update-secret \
                         --secret-string file:///tmp/secret_string.json \
                         --secret-id ${secret_name} \
                         --output text --query ARN)
    fi
    echo Secret ARN: ${secret_arn}
    echo VARIABLES for AWS CODEBUILD:
    echo name: [thing_name] value: [${secret_name}:thing_name]
    echo name: [thing_arn] value: [${secret_name}:thing_arn]
    echo name: [certificate] value: [${secret_name}:certificate]
    echo name: [privatekey] value: [${secret_name}:privatekey]
    echo name: [iotcore_endpoint] value: [${secret_name}:iotcore_endpoint]
    echo name: [da_endpoint] value: [${secret_name}:da_endpoint]
    echo name: [certificate_arn] value: [${secret_name}:certificate_arn]
}

function export_variants {
    _volatile_dir=$1
    _thing_name=$2
    _thing_arn=$3
    _policy_name=$4
    _policy_arn=$5
    _certificate_id=$6
    _certificate_arn=$7
    _export_file=${_volatile_dir}/${_thing_name}/exports

}

#
# Directory where all volatile artifacts reside.

mkdir -p ${volatile_dir}/${THING_NAME}

certificate_file=${volatile_dir}/${THING_NAME}/${THING_NAME}.crt.pem
pubkey_file=${volatile_dir}/${THING_NAME}/${THING_NAME}.key.pub.pem
privkey_file=${volatile_dir}/${THING_NAME}/${THING_NAME}.key.prv.pem

if test -f ${certificate_file}; then
    echo WARNING: Certificate already created in region for device, ensure you
    echo WARNING:   redeploy to physical device.
fi
if test -f ${pubkey_file}; then
    echo WARNING: Public key already created in region for device, ensure you
    echo WARNING:   redeploy to physical device.
fi
if test -f ${privkey_file}; then
    echo WARNING: Certificate created already in region for device, ensure you
    echo WARNING:   redeploy to physical device.
fi

create_certificate_devmode

if test $FORCE == 0; then
    thing_exists $THING_NAME
    if test $? == 1; then
        create_thing $THING_NAME
        if test $? == 1; then
            echo failed to create thing object.
            exit 1
        fi
    else
        get_thing_arn $THING_NAME
        if test $? == 1; then
            echo failed to fetch thing arn.
            exit 1
        fi
    fi
else
    create_thing $THING_NAME
    if test $? == 1; then
        echo failed to create thing object.
        exit 1
    fi
fi    

if test $FORCE == 0; then
    policy_exists $POLICY_NAME
    if test $? == 1; then
        create_policy $POLICY_NAME
        if test $? == 1; then
            echo failed to create policy object.
            exit 1
        fi
    else
        get_policy_arn $POLICY_NAME
        if test $? == 1; then
            echo failed to fetch policy arn.
            exit 1
        fi
    fi
else
    create_policy $POLICY_NAME
    if test $? == 1; then
        echo failed to create policy object.
        echo since you are running force, we assume that you want to reuse an existing policy.
    fi
fi

link_objects

iotcore_endpoint=$(aws iot describe-endpoint --endpoint-type iot:Data-ATS --output text --query endpointAddress)

if test ! -z ${SECRET_NAME}; then
    store_secret ${THING_NAME} ${THING_ARN} ${CERTIFICATE_ARN} ${certificate_file} ${privkey_file} ${iotcore_endpoint}
fi

EXPORTS_FILE=${volatile_dir}/${THING_NAME}/exports
echo "THING_NAME=${THING_NAME}"              > ${EXPORTS_FILE}
echo "THING_ARN=${THING_ARN}"               >> ${EXPORTS_FILE}
echo "POLICY_NAME=${POLICY_NAME}"           >> ${EXPORTS_FILE}
echo "POLICY_ARN=${POLICY_ARN}"             >> ${EXPORTS_FILE}
echo "CERTIFICATE_ID=${CERTIFICATE_ID}"     >> ${EXPORTS_FILE}
echo "CERTIFICATE_ARN=${CERTIFICATE_ARN}"   >> ${EXPORTS_FILE}
echo "CERTIFICATE_FILE=${certificate_file}" >> ${EXPORTS_FILE}
echo "PRIVATEKEY_FILE=${privkey_file}"      >> ${EXPORTS_FILE}
echo "IOTCORE_ENDPOINT=${iotcore_endpoint}" >> ${EXPORTS_FILE}
echo "DA_ENDPOINT=${da_endpoint}"           >> ${EXPORTS_FILE}

echo source the exports file for easy credential handling, i.e.
echo . ${EXPORTS_FILE}