#!/bin/bash

# This script installs Komodor's agent on your cluster, it uses helm and kubectl.
# You can find the repo at: https://github.com/komodorio/Install

printKomodorLogo() {
    echo "
    
    
                      ▄██████████████████████████████████
                   ▄██████████████████████████████████████
                 ▄█████▀                              ▀█████
                ▐████▀                                  ████▌
                ▐████         ▄▄▄            ▄▄         ▐███▌
                ▐████       ▄█████▄        ██████       ▐███▌
                ▐████      ▐███████       ███████▌      ▐███▌
                ▐████      ▐███████       ███████▌      ▐███▌
                ▐████       ██████▌       ▐██████       ▐███▌
                ▐████         ▀▀▀           ▀▀▀▀        ▐███▌
                ▐████                                   ▐███▌
                ▐████                                   ▐███▌
                ▐████                                   ▓███▌
                ▐█████▄                               ▄█████▀
                  ▀███████████████████████████████████████▀
                    ▀███████████████████████████████████▀
 
 
 
 ▐█▌                                                       ▐█▌
 ▐█▌                                                       ▐█▌
 ▐█▌  ▄█▀   ███████▄  █████████████  ▄█████████████  ▄███████▌ ▄███████▄ ▓█▄███
 ▐█▄██▌    ▐█▌    ██  ██   ▐█▌   ▐█▌ ██          ▓█▌ ██    ▐█▌ ██    ▐█▌ ▓█▌
 ▐█▀ ▀██   ▐█▌    ██  ██   ▐█▌   ▐█▌ ██          ▓█▌ ██    ▐█▌ ██    ▐█▌ ▓█▌
 ▐█▌   ██▄  ███████▀  ██   ▐█▌   ▐█▌ ▀█████████████  ▀███████▌ ▀███████▀ ▓█▌
"
}

printEnterClusterName() {
    echo "
                                                                                                                             
                 ,--.                          ,--.                ,--.                                                      
 ,---. ,--,--, ,-'  '-. ,---. ,--.--.     ,---.|  |,--.,--. ,---.,-'  '-. ,---. ,--.--.    ,--,--,  ,--,--.,--,--,--. ,---.  
| .-. :|      \'-.  .-'| .-. :|  .--'    | .--'|  ||  ||  |(  .-''-.  .-'| .-. :|  .--'    |      \' ,-.  ||        || .-. : 
\   --.|  ||  |  |  |  \   --.|  |       \ '--.|  |'  ''  '.-'  ') |  |  \   --.|  |       |  ||  |\ '-'  ||  |  |  |\   --. 
 '----''--''--'  '--'   '----''--'        '---''--' '----' '----'  '--'   '----''--'       '--''--' '--'--''--'--'--' '----' 
                                                                                                                             
"
}

printSuccess() {
    echo "
                                                 ,---.,---. 
 ,---.                                           |   ||   | 
'   .-' ,--.,--. ,---. ,---. ,---.  ,---.  ,---. |  .'|  .' 
'.  '-. |  ||  || .--'| .--'| .-. :(  .-' (  .-' |  | |  |  
.-'    |'  ''  '\ '--.\ '--.\   --..-'  ').-'  ')'--' '--'  
'-----'  '----'  '---' '---' '----''----' '----' .--. .--.  
                                                 '--' '--'  
"

    echo "Open https://app.komodor.com/ to start using Komodor"
}

sendClusterConnectivityErrorEvent() {
    # We collect error logs to learn about and improve the installation process.

    echo 'Running the following commands for troubleshooting and analytics:'
    echo "$ kubectl get ns default "
    echo "$ kubectl get ns "

    getNsDefault="$(kubectl get ns default 2>&1)"
    getAllNs="$(kubectl get ns 2>&1)"

    properties='{"getAllNs": "'"$getAllNs"'", "getNsDefault": "'"$getNsDefault"'", "email": "'"$USER_EMAIL"'", "origin": "self-serve-script", "scriptType": "bash"}'

    data='{"eventName": "USER_CLUSTER_CONNECTIVITY_SUCCESS_ERROR","userId": "'$USER_EMAIL'", "properties": '$properties'}'

    curl --location --request POST 'https://api.komodor.com/analytics/segment/track' \
        --header 'api-key: '$USER_EMAIL'' \
        --header 'Content-Type: application/json' \
        -d @<(
            cat <<EOF
$data
EOF
        )

}

sendAnalytics() {
    # We use analytics to keep track of what works and what doesn't work in our script, with the intention of creating the best installation experience possible.
    # argument 1 = Event type

    curl --location --request POST 'https://api.komodor.com/analytics/segment/track' \
        --header 'api-key: '$USER_EMAIL'' \
        --header 'Content-Type: application/json' \
        --data-raw '{
        "eventName": "'$1'",
        "userId": "'$USER_EMAIL'",
        "properties": {
            "email": "'$USER_EMAIL'",
            "origin": "self-serve-script",
            "scriptType": "bash"
        }
    }'
}

sendContextAnalytics() {
    # We use analytics to keep track of what works and what doesn't work in our script, with the intention of creating the best installation experience possible.
    # argument 1 = Event type
    eventName="USER_CONTEXT_OUTPUT_$1"
    properties='{"context": "'"$2"'", "email": "'"$USER_EMAIL"'", "origin": "self-serve-script", "scriptType": "bash"}'
    data='{"eventName": "'$eventName'","userId": "'$USER_EMAIL'", "properties": '$properties'}'

    curl --location --request POST 'https://api.komodor.com/analytics/segment/track' \
        --header 'api-key: '$USER_EMAIL'' \
        --header 'Content-Type: application/json' \
        -d @<(
            cat <<EOF
$data
EOF
        )
}

sendErrorAnalytics() {
    # We collect error logs to learn about and improve the installation process.
    # argument 1 = The event name
    # argument 2 = The error message

    properties='{"error": "'"$2"'", "email": "'"$USER_EMAIL"'", "origin": "self-serve-script", "scriptType": "bash"}'
    data='{"eventName": "'$1'","userId": "'$USER_EMAIL'","properties": '$properties'}'

    curl --location --request POST 'https://api.komodor.com/analytics/segment/track' \
        --header 'api-key: '$USER_EMAIL'' \
        --header 'Content-Type: application/json' \
        -d @<(
            cat <<EOF
$data
EOF
        )

}

STEPS_COUNT=6
DEFAULT_CLUSTER_NAME=default

printStep() {
    echo -e "-------------$1/$STEPS_COUNT----------------"
    echo -e "$2\n"
}

isValidClusterName() {
    # This validation follows the official K8s guide to valid object and resource names.
    # Learn more: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/
    local CLUSTER_NAME=$1

    if [[ -z "$CLUSTER_NAME" ]]; then
        return 0
    fi
    if [[ "$CLUSTER_NAME" =~ ^[a-z] ]] && [[ "$CLUSTER_NAME" =~ ^[a-z0-9.-]+$ ]] && [[ "$CLUSTER_NAME" =~ ^([a-z]([a-z0-9-]*[a-z0-9])?\.)*([a-z]([a-z0-9-]*[a-z0-9])?)$ ]] && [[ "$CLUSTER_NAME" =~ [a-z0-9]$ ]]; then
        return 1
    else
        return 0
    fi
}

getValidClusterName() {
    # Get cluster name from kubectl current context, format and strip it of unnecessary characters and symbols, and validate it.
    # If the validation succeeds, use the real cluster name; otherwise, use the default name.
    local KUBECTL_CLUSTER_NAME=$1
    STRIP_CLUSTER_NAME=$(echo $KUBECTL_CLUSTER_NAME | cut -d "/" -f2)
    isValidClusterName $STRIP_CLUSTER_NAME
    if [ $? -eq 1 ]; then
        echo $STRIP_CLUSTER_NAME
    else
        echo $DEFAULT_CLUSTER_NAME
    fi
}

getUserCustomClusterName() {
    # Get cluster name from user
    echo -n "Enter cluster display name: "
    read -r FINAL_CLUSTER_NAME
    echo
    isValidClusterName $FINAL_CLUSTER_NAME
    if [ $? -eq 1 ]; then
        return
    else
        echo "This is an invalid cluster name. Using default cluster name."
        FINAL_CLUSTER_NAME=$DEFAULT_CLUSTER_NAME
    fi
}

userChooseClusterName() {
    # Get cluster name from user
    local USER_CLUSTER_NAME=$1
    printEnterClusterName
    echo "Choose your cluster display name in Komodor"
    echo "1. $USER_CLUSTER_NAME"
    echo "2. Enter cluster name manually"

    echo "Enter your choice [1/2]:"
    read choice

    if [ "$choice" = "1" ]; then
        echo -e "You chose cluster name: $USER_CLUSTER_NAME\n"
        FINAL_CLUSTER_NAME=$USER_CLUSTER_NAME
    elif [ "$choice" = "2" ]; then
        getUserCustomClusterName
    else
        echo -e "\nWrong input\n"
        userChooseClusterName $USER_CLUSTER_NAME
    fi
}

validateUserParams() {
    if [[ -z "$HELM_API_KEY" ]]; then
        echo "ERROR: Komodor installation script needs HELM_API_KEY session variable in order to run."
        exit 1
    fi

    if [[ -z "$USER_EMAIL" ]]; then
        echo "ERROR: Komodor installation script needs USER_EMAIL session variable in order to run."
        exit 1
    fi
}

startExecuting() {
    echo "***** This might take about 3 minutes *****"
    printKomodorLogo
    printStep 1 "Starting installation"
    sendAnalytics USER_RAN_SCRIPT_INSTALATION
    validateUserParams
}

checkKubectlRequirements() {
    printStep 2 "Checking for existing kubectl installation"
    if ! command -v kubectl &>/dev/null; then
        echo "kubectl isn't installed on your machine please install kubectl and run again."
        echo "You can find the download links here: https://kubernetes.io/docs/tasks/tools/"
        exit 1
    fi
    echo "Kubectl is already installed!"
    sendAnalytics USER_HAS_KUBECTL
}

checkConnectionToCluster() {
    printStep 4 "Checking Cluster Connection with command: kubectl get ns default"
    if ! kubectl get ns default >/dev/null 2>&2; then
        echo 'Kubernetes cluster connectivity test failed... please make sure your cluster is up and your context is correct.' >&2
        sendClusterConnectivityErrorEvent
        exit 1
    fi
    echo 'Kubernetes cluster connectivity test success!'
    sendAnalytics USER_CLUSTER_CONNECTIVITY_SUCCESS
}

setClusterName() {
    # This function set global var FINAL_CLUSTER_NAME, holds the cluster name the user will choose
    printStep 4 "Choosing cluster name"
    local CLUSTER_NAME=$(kubectl config current-context)
    echo -e "We're going to install komodor agent on cluster: \n${CLUSTER_NAME}"

    local KUBECTL_VALID_CLUSTER_NAME=$(getValidClusterName $CLUSTER_NAME)
    # we use dev tty in order to read from user input after overriding it to /dev/null
    userChooseClusterName $KUBECTL_VALID_CLUSTER_NAME </dev/tty
    sendAnalytics USER_CHOSE_CLUSTER_NAME
}

chooseContext() {
    # Get all k8s contexts
    printStep 3 "Select the relevant kube context"
    contexts=$(kubectl config get-contexts -o name 2>&1)

    if [ $? -eq 0 ]; then
        sendContextAnalytics SUCCESS "$contexts"
        # Print contexts to user and ask them to select one
        echo "Please select a context:"
        select context in $contexts; do
            if [[ -n $context ]]; then
                sendAnalytics USER_CHOSE_CONTEXT_SUCCESS
                # Switch to selected context
                echo "Switching context to: "
                kubectl config use-context $context
                echo "Context successfully changed to: $context"
                break
            else
                echo "Invalid selection. Please try again."
            fi
        done
    else
        sendContextAnalytics ERROR "$contexts"
        echo "An error occured when trying to execute: $ kubectl config get-contexts -o name"
        exit 1
    fi

}

checkHelmRequirement() {
    # Check if Helm is installed
    printStep 6 "Checking Helm Installation"
    if which helm >/dev/null; then
        echo 'Helm is installed'
    else
        echo 'Helm is not installed...'
        echo "You can get it here: https://helm.sh/docs/intro/install/"
        exit 1
    fi
    sendAnalytics USER_HAS_HELM
}

installKomodorHelmPackage() {
    # Install Komodor's agent on your cluster!
    printStep 7 "Installing Komodor"
    echo "Running the following helm commands:"
    echo "- $ helm repo add komodorio https://helm-charts.komodor.io"
    echo "- $ helm repo update"
    echo "- $ helm upgrade --install k8s-watcher komodorio/k8s-watcher --set apiKey=$HELM_API_KEY --set watcher.clusterName=$FINAL_CLUSTER_NAME --wait --timeout=90s"
    INSTALL_OUTPUT=$(helm repo add komodorio https://helm-charts.komodor.io 2>&1)
    if [ $? -eq 0 ]; then
        echo "Added komodor chart repository successfully!"
    else
        echo "Failed adding komodor chart repository..."
        echo "$INSTALL_OUTPUT"
        sendErrorAnalytics "USER_INSTALL_KOMODOR_SCRIPT_REPO_ERROR" "$INSTALL_OUTPUT"
        exit 1
    fi
    echo "Installing Komodor, this might take a minute"
    helm repo update >/dev/null 2>&2
    INSTALL_OUTPUT=$(helm upgrade --install k8s-watcher komodorio/k8s-watcher --set apiKey=$HELM_API_KEY --set watcher.clusterName=$FINAL_CLUSTER_NAME --wait --timeout=90s 2>&1)
    if [ $? -eq 0 ]; then
        echo "Komodor installed successfully!"
        sendAnalytics USER_INSTALL_KOMODOR_SCRIPT_SUCCESS
    else
        echo "Komodor install failed..."
        echo "$INSTALL_OUTPUT"
        sendErrorAnalytics "USER_INSTALL_KOMODOR_SCRIPT_SUCCESS_ERROR" "$INSTALL_OUTPUT"
        DIAGNOSTICS=$(helm history k8s-watcher -o json 2>&1)
        sendErrorAnalytics "LAST_STEP_ERROR_DIAGNOSTICS_V2" "$DIAGNOSTICS"
        exit 1
    fi
    printSuccess
}

startExecuting            # step 1
checkKubectlRequirements  # step 2
chooseContext             # step 3
checkConnectionToCluster  # step 4
setClusterName            # step 5
checkHelmRequirement      # step 6
installKomodorHelmPackage # step 7