#
#
###############################################################
################   Create a new Function   ####################
###############################################################
#
#
#
#  
# STEPS
# 1. Call this file
#    
#     source ./Create_Function.sh
#       
#       /API/Create_Function
#

. ./@Core/Scripts/templates.sh
. ./@Core/Scripts/createMenu.sh

###############################################################
################   REUSABLE FUNCTIONS HERE  ###################
###############################################################

FAIL_FUNCTION () {
    echo "${RED}Only ${YELLOW}true${RED} or ${YELLOW}false${RED} are accepted."
    echo "\nPlease try again${NC}"

    echo "\n\n${FAIL_TEXT}"
    exit 0
}

# Create a new function given namespace and function name
function create_function () {
    local NAMESPACE=$1
    local FUNCTION_NAME=$2
    local PRIVATE_FUNCTION=$3
    local ENDPOINT=$4
    local DIRECTORY="./API/$NAMESPACE/$FUNCTION_NAME/"
    local PREVIOUS_COPY="true"

    if [ ! -d "$DIRECTORY""1.0.0" ]
    then
        local DIRECTORY_VERSION="./API/$NAMESPACE/$FUNCTION_NAME/1.0.0"
        local VERSION_NUMBER="1.0.0"
    else
        # THe Namespace Exists
        echo "\n${DARK_GRAY}Updating existing function... ${NC}\n"
        echo "${NC}Current Versions: "
        for i in `ls $DIRECTORY | sort -V`; do 
            local LATEST_VERSION=$i
            echo $i; 
        done;
        echo " "
        echo "${WHITE}Enter a new Version Number? ${GREEN}"
        read VERSION_NUMBER
        local DIRECTORY_VERSION="./API/$NAMESPACE/$FUNCTION_NAME/$VERSION_NUMBER"
        echo "${WHITE}Copy files from previous version ${GREEN}"
        local BOOLEAN_OPTIONS=("true" "false")
        select_option "${BOOLEAN_OPTIONS[@]}"
        local CHOICE=$?
        PREVIOUS_COPY="${BOOLEAN_OPTIONS[$CHOICE]}"
    fi

    local FIND="."
    local REPLACE="_"
    # notice the the str isn't prefixed with $
    #    this is just how this feature works :/
    local FUNCTION_VERSION_REFERENCE=${VERSION_NUMBER//$FIND/$REPLACE}

    local ACTUAL_FUNCTION_NAME="$NAMESPACE""_""$FUNCTION_NAME""_""$FUNCTION_VERSION_REFERENCE"


    echo "\n${YELLOW}Check the information below${NC}"

    echo "\n${NC}Namespace
    ${GREEN}$NAMESPACE"
    echo "${NC}Function
    ${GREEN}$FUNCTION_NAME"
    echo "${NC}Version
    ${GREEN}$VERSION_NUMBER"
    echo "${NC}Authentication"
    if [ $PRIVATE_FUNCTION = "true" ]
    then
        echo "    ${GREEN}$PRIVATE_FUNCTION"
    else
        echo "    ${RED}$PRIVATE_FUNCTION"
    fi
    echo "${NC}External Endpoint"
    if [ $ENDPOINT = "true" ]
    then
        echo "    ${GREEN}$ENDPOINT"
    else
        echo "    ${RED}$ENDPOINT"
    fi

    echo "\n${WHITE}Is this correct? ${NC}(Press enter to continue...)"

    read CORRECT_AND_CONTINUE


    if [ ! -d "$DIRECTORY_VERSION" ]
    then
        if [ ! -d "./API/$NAMESPACE" ]
        then
            # echo "${NC}Namespace doesn't exist. Creating it now"
            mkdir ./API/$NAMESPACE
            echo "\n1. Namespace created"
            mkdir $DIRECTORY
        else
            if [ ! -d "$DIRECTORY" ]
            then
                # THe Namespace Exists
                echo "\n${NC}1. Function Doesn't Exist. Creating the Function Name now."
                mkdir $DIRECTORY
            fi

        fi
            # Copy a clean version of the packages across..

        # echo "${NC}Creating Version $VERSION_NUMBER now"
        mkdir $DIRECTORY_VERSION

        if [ $VERSION_NUMBER = '1.0.0' ] || [ $PREVIOUS_COPY == 'false' ]
        then
            # Copy a new clean file in
            # Copy a clean version of the packages across..

            # echo "Copying directory..."
            cp -R ./@Core/NPM-Package-Helpers/FunctionName/* $DIRECTORY_VERSION
            # echo " "
            
            # Changing the function Name in the index file
            # echo "Changing File Names for index.ts ..."
            sed -i -- "s/FunctionName/$ACTUAL_FUNCTION_NAME/g" $DIRECTORY_VERSION/index.ts
            # echo " "

            # Changing the function Name in the README file
            # echo "Changing File Names for README.md ..."
            sed -i -- "s/FunctionName/$ACTUAL_FUNCTION_NAME/g" $DIRECTORY_VERSION/README.md
            # echo " "

            # Changing the function Name in the Test file
            # echo "Changing File Names for spec.ts ..."
            sed -i -- "s/FunctionName/$ACTUAL_FUNCTION_NAME/g" $DIRECTORY_VERSION/index.spec.ts
            sed -i -- "s/FunctionName/$ACTUAL_FUNCTION_NAME/g" $DIRECTORY_VERSION/_data/failData.ts

            # # Creating the package.json file, so it's a NPM package
            # # echo "Creating the package.json"
            # # JSON_PACKAGE_NAME="$NAMESPACE""_""$FUNCTION_NAME"
            # JSON_PACKAGE_NAME="`echo "$NAMESPACE""_""$FUNCTION_NAME" | tr '[:upper:]' '[:lower:]'`"
            # sed -i -- "s/original_function_name/$FUNCTION_NAME/g" $DIRECTORY_VERSION/package.json
            # sed -i -- "s/function_name/$JSON_PACKAGE_NAME/g" $DIRECTORY_VERSION/package.json
            # sed -i -- "s/function_description/$DESCRIPTION/g" $DIRECTORY_VERSION/package.json
            # sed -i -- "s/version_number/$VERSION_NUMBER/g" $DIRECTORY_VERSION/package.json
            # sed -i -- "s/namespace/$NAMESPACE/g" $DIRECTORY_VERSION/package.json

            # echo " "

            # Removing the copy files that sed -i created
            # rm -f $DIRECTORY_VERSION/package.json--
            rm -f $DIRECTORY_VERSION/README.md--
            rm -f $DIRECTORY_VERSION/index.ts--
            rm -f $DIRECTORY_VERSION/index.spec.ts--
            rm -f $DIRECTORY_VERSION/_data/failData.ts--
            # echo " "
            local ACTUAL_DIRECTORY="API/$NAMESPACE/$FUNCTION_NAME/$VERSION_NUMBER"

        else
            # Copy the last version files over, and change the file names
            echo "\n${NC}1. Copying previous version"

            local DIRECTORY_LAST_VERSION="./API/$NAMESPACE/$FUNCTION_NAME/$LATEST_VERSION"
            local FUNCTION_VERSION_REFERENCE_LAST_VERSION=${LATEST_VERSION//$FIND/$REPLACE}
            local FUNCTION_NAME_LAST_VERSION="$NAMESPACE""_""$FUNCTION_NAME""_""$FUNCTION_VERSION_REFERENCE_LAST_VERSION"
            # echo "Copying directory..."
            cp -R $DIRECTORY_LAST_VERSION/* $DIRECTORY_VERSION
            # echo " "
            
            # Changing the function Name in the index file
            # echo "Changing File Names for index.ts ..."
            sed -i -- "s/$FUNCTION_NAME_LAST_VERSION/$ACTUAL_FUNCTION_NAME/g" $DIRECTORY_VERSION/index.ts
            # echo " "

            # Changing the function Name in the Test file
            # echo "Changing File Names for test.ts ..."
            sed -i -- "s/$FUNCTION_NAME_LAST_VERSION/$ACTUAL_FUNCTION_NAME/g" $DIRECTORY_VERSION/index.spec.ts
            # echo " "

            # Changing the function Name in the README file
            # echo "Changing File Names for README.md ..."
            sed -i -- "s/$FUNCTION_NAME_LAST_VERSION/$ACTUAL_FUNCTION_NAME/g" $DIRECTORY_VERSION/README.md
            # echo " "

            # # Creating the package.json file, so it's a NPM package
            # # echo "Creating the package.json"
            # NEW_DESCRIPTION='  "description": "'$DESCRIPTION'",'
            # sed -i -- "4s/.*/$NEW_DESCRIPTION/" $DIRECTORY_VERSION/package.json
            # sed -i -- "s/function_description/$DESCRIPTION/g" $DIRECTORY_VERSION/package.json
            # sed -i -- "s/$LATEST_VERSION/$VERSION_NUMBER/g" $DIRECTORY_VERSION/package.json
            # echo " "

            # Removing the copy files that sed -i created
            # rm -f $DIRECTORY_VERSION/package.json--
            rm -f $DIRECTORY_VERSION/README.md--
            rm -f $DIRECTORY_VERSION/index.ts--
            rm -f $DIRECTORY_VERSION/index.spec.ts--
            # echo " "
            local ACTUAL_DIRECTORY="API/$NAMESPACE/$FUNCTION_NAME/$LATEST_VERSION"

        fi


        # DIRECTORY_LAST_VERSION="./API/$NAMESPACE/$FUNCTION_NAME/$LATEST_VERSION"

        # Add the actual directory to the packageFolders file as a reference for deployment
#         printf "$ACTUAL_DIRECTORY
# "  >> ./deploy/packageFolders.txt  

        if [ $PRIVATE_FUNCTION = "true" ]
        then
            echo "\n2. Adding the private function statement"
            local FIND_LOGIN_REQUIRED_COMMENT='\/\/ NewLoginRequiredGoesHere'
            local REPLACE_PRIVATE_FUNCTION="$ACTUAL_FUNCTION_NAME: true,
  \/\/ NewLoginRequiredGoesHere"
            perl -i.bak -pe "s/$FIND_LOGIN_REQUIRED_COMMENT/$REPLACE_PRIVATE_FUNCTION/g" ./API/index.ts 
        fi

        if [ $ENDPOINT = "true" ]
        then
            echo "\n3. Adding function as an endpoint"
            local FIND_ENDPOINT_COMMENT='\/\/ NewEndpointGoesHere'
            local REPLACE_PRIVATE_FUNCTION="$ACTUAL_FUNCTION_NAME: true,
  \/\/ NewEndpointGoesHere"
            perl -i.bak -pe "s/$FIND_ENDPOINT_COMMENT/$REPLACE_PRIVATE_FUNCTION/g" ./API/index.ts 
        fi

        rm -f ./API/index.ts.bak

        echo "\n\n${BLACK_TEXT_ON_GREEN_BACKGROUND} DONE! Function has been created in Folder: $DIRECTORY_VERSION  ${NC}"

        echo "\n${GREEN}1. Write Tests."

        echo "\n${GREEN}2. Update README.md"


    else
        # Copy latest package version across

        echo "${RED}Function with this version number already exists."
        echo "Please try again${NC}"
        echo "    ..."
        echo "    ..."
        echo "${FAIL_TEXT}"
    fi
}

###############################################################
#####################   CONSTANTS   ###########################
###############################################################

# Folders to be ignored in namespace directory
IGNORE_API_FOLDERS=("./API/CoreHelpers/" "./API/Core/")
# The default name for creating a new function
NEW_FUNCTION="Create a new function"
# PASCAL CASE REGEX
PASCAL_REGEX='^[A-Z][a-z]+([A-Z][a-z]+)*$'

###############################################################
################   INTERNAL STATE MUTATIONS  ##################
###############################################################

# The currently selected namespace (string)
NAMESPACE=""
# The currently selected function name (string)
FUNCTION_NAME=""
# The lines to remove from the terminal (int)
LINES_TO_REMOVE=0
# The current private state of a function (true || false)
PRIVATE_FUNCTION=""
# The current external state of an endpoint (true || false)
ENDPOINT=""

###############################################################
####################   MENU HELPERS   #########################
###############################################################

# Erase lines and set lines to remove to 0
function clear_lines {
    erase_lines $LINES_TO_REMOVE
    LINES_TO_REMOVE=0
}

# Initialise create function program and set currently selected namespace
function create_function_init {
    local NAMESPACES=()
    for name in ./API/*/
    do
        if ! [[ ${IGNORE_API_FOLDERS[*]} =~ "$name" ]]; then
            NAMESPACES+=(`basename ${name}`)
        fi
    done

    NAMESPACES+=("$NEW_FUNCTION")

    printf "${RED}Create a new function in one of the following namespaces${NC}\n"
    printf "${DARK_GRAY}   Use the arrow keys to move around... ${NC}\n"

    select_option "${NAMESPACES[@]}"
    local CHOICE=$?
    NAMESPACE="${NAMESPACES[$CHOICE]}"

    # Clearing lines
    local BUFFER=3
    LINES_TO_REMOVE=$((${#NAMESPACES[@]}+$BUFFER))
    clear_lines
}

# Initiate flow for creating a new function
function create_new_function {
    # Namespace menu
    printf "Namespace:${GREEN} "
    
    while [ true ]
    do
        LINES_TO_REMOVE=$(($LINES_TO_REMOVE+2))
        read NAMESPACE
        if [[ ! $NAMESPACE  =~ $PASCAL_REGEX ]]
            then
                echo "${RED} ! $NAMESPACE is not a PascalCase ${NC}"
                printf "Namespace:${GREEN} "
            else
                clear_lines
                printf "${NC}Namespace:${GREEN} $NAMESPACE\n"
                break
        fi
    done
    
    # Function name menu
    printf "\r${NC}Function name:${GREEN} "
    while [ true ]
    do
        LINES_TO_REMOVE=$(($LINES_TO_REMOVE+2))
        read FUNCTION_NAME
        if [[ ! $FUNCTION_NAME  =~ $PASCAL_REGEX ]]
            then
                echo "${RED} ! $FUNCTION_NAME is not a PascalCase ${NC}"
                printf "Function name:${GREEN} "
            else
                clear_lines
                printf "${NC}Function name:${GREEN} $FUNCTION_NAME\n"
                break      
        fi
    done

    # Authentication menu
    printf "${NC}Does this function require a user to have authenticated JWT to access it?\n"
    local BOOLEAN_OPTIONS=("true" "false")
    select_option "${BOOLEAN_OPTIONS[@]}"
    local CHOICE=$?

    PRIVATE_FUNCTION="${BOOLEAN_OPTIONS[$CHOICE]}"

    # Clearing lines
    local BUFFER=3
    LINES_TO_REMOVE=$((${#BOOLEAN_OPTIONS[@]}+$BUFFER))
    clear_lines
    printf "Authentication: ${GREEN}$PRIVATE_FUNCTION${NC}"

    # Endpoint menu
    echo "\n${NC}Will this be an external endpoint?"
    select_option "${BOOLEAN_OPTIONS[@]}"
    local CHOICE=$?
    ENDPOINT="${BOOLEAN_OPTIONS[$CHOICE]}"

    # Clearing lines
    local BUFFER=3
    LINES_TO_REMOVE=$((${#BOOLEAN_OPTIONS[@]}+$BUFFER))
    clear_lines
    printf "External endpoint: ${GREEN}$ENDPOINT${NC}\n"

    create_function $NAMESPACE $FUNCTION_NAME $PRIVATE_FUNCTION $ENDPOINT
}

# Initiate flow for modifying an existing function
function modify_existing_function {
    # Selecting function
    printf "Namespace:${GREEN} $NAMESPACE ${NC}\n"

    local FUNCTION_NAMES=()
    for name in ./API/$NAMESPACE/*/
    do
        FUNCTION_NAMES+=(`basename ${name}`)
    done

    printf "${NC}Select one of the following functions: \n"

    # Function Menu
    FUNCTION_NAMES+=("$NEW_FUNCTION")
    select_option "${FUNCTION_NAMES[@]}"
    local CHOICE=$?
    FUNCTION_NAME=${FUNCTION_NAMES[$CHOICE]}

    # Clearing lines
    local BUFFER=2
    if [ "${FUNCTION_NAME}" != "$NEW_FUNCTION" ]; then
        LINES_TO_REMOVE=$((${#FUNCTION_NAMES[@]}+$BUFFER))
    else
        LINES_TO_REMOVE=$((${#FUNCTION_NAMES[@]}+$BUFFER+1))
    fi
    clear_lines

    # Check whether new function needs to be created
    if [ "${FUNCTION_NAME}" != "$NEW_FUNCTION" ]
    then
        LINES_TO_REMOVE=$((${LINES_TO_REMOVE}+2))
        clear_lines
        printf "Function name:${GREEN} ${FUNCTION_NAME} ${NC}\n"
    else
        printf "Function name:${GREEN} "
        while [ true ]
        do
            LINES_TO_REMOVE=$((${LINES_TO_REMOVE}+2))
            read FUNCTION_NAME
            if [[ $FUNCTION_NAME  =~ $PASCAL_REGEX ]]
                then
                    break  
                else
                    echo "${RED} ! $FUNCTION_NAME is not a PascalCase ${NC}"
                    printf "Function name:${GREEN} "
            fi
        done
        clear_lines
        printf "${NC}Function name:${GREEN} $FUNCTION_NAME\n"
    fi
    
    # Authentication menu
    printf "${NC}Does this function require a user to have authenticated JWT to access it?\n"
    local BOOLEAN_OPTIONS=("true" "false")
    select_option "${BOOLEAN_OPTIONS[@]}"
    local CHOICE=$?

    # Clear lines
    local BUFFER=3
    LINES_TO_REMOVE=$((${#BOOLEAN_OPTIONS[@]}+$BUFFER))
    clear_lines

    PRIVATE_FUNCTION="${BOOLEAN_OPTIONS[$CHOICE]}"
    printf "Authentication: ${GREEN}$PRIVATE_FUNCTION${NC}"

    # Endpoint menu
    echo "\n${NC}Will this be an external endpoint?"
    select_option "${BOOLEAN_OPTIONS[@]}"
    local CHOICE=$?
    ENDPOINT="${BOOLEAN_OPTIONS[$CHOICE]}"

     # Clear lines
    local BUFFER=3
    LINES_TO_REMOVE=$((${#BOOLEAN_OPTIONS[@]}+$BUFFER))
    clear_lines

    printf "External endpoint: ${GREEN}$ENDPOINT${NC}\n"

    create_function $NAMESPACE $FUNCTION_NAME $PRIVATE_FUNCTION $ENDPOINT
}

###############################################################
################   Main Program flow here   ###################
###############################################################

function main {
    create_function_init

    if [ "$NAMESPACE" = "$NEW_FUNCTION" ]
    then
        create_new_function
    else
        modify_existing_function
    fi
}

main
