#!/bin/bash

# Author: Jakub Konvicka
# Contact: jakub.konvicka@vsb.cz
# Web: https://heappe.eu/
# Support: support.heappe@it4i.cz
# Description: This script creates the directory structure for a new HEAppE project and sets up the environment for the HEAppE middleware.

# Define the base path for the project directory
BASE_PATH="/opt/heappe"

echo "-------------------------------------------------"
echo "HEAppE Middleware Environment Setup - HPC version"
echo "-------------------------------------------------"

# Initialize variables
PROJECT_DIRECTORY=""
SET_DEFAULTS=""

# Parse command-line arguments
while [[ "$#" -gt 0 ]]; do
    case $1 in
        -p|--project) PROJECT_DIRECTORY="$2"; shift ;;
        -d|--defaults) SET_DEFAULTS="Y" ;;
        *) echo "Unknown parameter passed: $1"; exit 1 ;;
    esac
    shift
done

# Prompt for default values if not set by flag
if [ -z "$SET_DEFAULTS" ]; then
    echo "Do you want to set up default values for the environment variables? [Y/n]"
    read -r SET_DEFAULTS

    if [ -z "$SET_DEFAULTS" ]; then
        SET_DEFAULTS="Y"
    fi
fi

# Define the project directory variable if not provided by flag
if [ -z "$PROJECT_DIRECTORY" ]; then
    # Loop until a valid project directory name is provided
    while [ -z "$PROJECT_DIRECTORY" ]; do
        echo -n "Enter project name: "
        read -r PROJECT_DIRECTORY

        # Check if the project directory is empty
        if [ -z "$PROJECT_DIRECTORY" ]; then
            echo "Project name cannot be empty."
            continue
        fi
    done
fi

echo "Creating structure for project: $PROJECT_DIRECTORY ..."

# Create the base directory if it doesn't exist
if [ ! -d "$BASE_PATH" ]; then
    echo "Creating base directory: $BASE_PATH ..."
    mkdir -p "$BASE_PATH"
    chmod -R 700 "$BASE_PATH"
fi

# Create subdirectories if they don't exist
cd "$BASE_PATH" || exit
for subdir in projects confs; do
    if [ ! -d "$subdir" ]; then
        echo "Creating directory: $subdir ..."
        mkdir "$subdir"
        chmod -R 700 "$subdir"
    fi
done

# Create project directory structure
cd projects || exit

# Check if the project directory already exists
if [ -d "$PROJECT_DIRECTORY" ]; then
    echo "Project directory structure for $PROJECT_DIRECTORY already exists."
    read -p "Do you want to delete it and start over? (Y/n): " choice
    if [ -z "$choice" ]; then
        choice="Y"
    fi
    while [ "$choice" != "Y" ] && [ "$choice" != "y" ] && [ "$choice" != "N" ] && [ "$choice" != "n" ]; do
        echo "Please enter Y/y for yes or N/n for no."
        read -p "Do you want to delete it and start over? (Y/n): " choice
    done
    if [ "$choice" = "Y" ] ||[ "$choice" = "y" ]; then
        echo "Deleting existing project directory structure..."
        rm -rf "$PROJECT_DIRECTORY"
        echo "Deleted successfully. Creating new project directory structure..."
    else
        echo "Keeping existing project directory structure. Exiting."
        exit 255
    fi
fi

# Create the project directory structure
echo "Creating project directory structure for: $BASE_PATH/projects/$PROJECT_DIRECTORY ..."
mkdir -p "$PROJECT_DIRECTORY/app/keys" \
        "$PROJECT_DIRECTORY/app/logs" \
        "$PROJECT_DIRECTORY/app/confs" \
        "$PROJECT_DIRECTORY/ssh_agent/keys" \
        "$PROJECT_DIRECTORY/docker_configurations"

# Set permissions
chmod -R 700 "$PROJECT_DIRECTORY"
echo "Project directory structure created successfully."

# Navigate to the docker configurations directory
cd "$PROJECT_DIRECTORY/docker_configurations" || exit

# Define default values for the environment variables
DEFAULT_COMPOSE_PROJECT_NAME="heappe"
DEFAULT_HOST_SSHAGENT_NAME="sshagent"
DEFAULT_HOST_SSHAGENT_HOST_MAP_FOLD_PATH="$BASE_PATH/projects/$PROJECT_DIRECTORY/ssh_agent/keys"
DEFAULT_HOST_SSHAGENT_CONTAINER_MAP_FOLD_PATH="/opt/heappe/sshagent_keys:ro"
DEFAULT_HOST_MSSQL_NAME="mssql"
DEFAULT_HOST_MSSQL_PORT="6000"
DEFAULT_HOST_MSSQL_PASSWORD="Passw0rd"
DEFAULT_HOST_APP_NAME="HEAppE"
DEFAULT_HOST_APP_PORT="5000"
DEFAULT_HOST_APP_HOST_MAP_FOLD_NAME="$BASE_PATH/projects/$PROJECT_DIRECTORY/app"
DEFAULT_HOST_APP_CONTAINER_MAP_FOLD_PATH="/opt/heappe"
DEFAULT_HOST_DATA_STAGING_NAME="DataStaging"
DEFAULT_HOST_DATA_STAGING_PORT="5001"
DEFAULT_HOST_DATA_STAGING_HOST_MAP_FOLD_NAME="$BASE_PATH/projects/$PROJECT_DIRECTORY/app"
DEFAULT_HOST_DATA_STAGING_CONTAINER_MAP_FOLD_PATH="/opt/heappe"

# Function to check if password meets complexity requirements
check_password_complexity() {
    local password=$1
    local username=$2

    # Check if password contains username
    if [[ $password == *"$username"* ]]; then
        echo "Password cannot contain the username."
        return 1
    fi

    # Check if password is at least eight characters long
    if [ ${#password} -lt 8 ]; then
        echo "Password must be at least eight characters long."
        return 1
    fi

    # Count number of character categories in the password
    local categories=0
    if [[ $password =~ [A-Z] ]]; then
        ((categories++))
    fi
    if [[ $password =~ [a-z] ]]; then
        ((categories++))
    fi
    if [[ $password =~ [0-9] ]]; then
        ((categories++))
    fi
    if [[ $password =~ [!@#\$%^] ]]; then
        ((categories++))
    fi

    # Check if password contains characters from at least three categories
    if [ $categories -lt 3 ]; then
        echo "Password must contain characters from at least three of the following categories: uppercase letters, lowercase letters, digits, special characters."
        return 1
    fi

    # Password meets complexity requirements
    return 0
}

# Function to read user input or use default value
read_or_default() {
    # Check if default values should be used
    if [ "$SET_DEFAULTS" == "Y" ] || [ "$SET_DEFAULTS" == "y" ]; then
        echo "$2"
        return
    fi
    local prompt=$1
    local default=$2
    local input
    read -r -p "$prompt [$default]: " input
    echo "${input:-$default}"
}

echo "Please provide the following values for the environment variables:"
echo "Note: Press Enter to use the default value in square brackets."

COMPOSE_PROJECT_NAME=$(read_or_default "Compose project name" $DEFAULT_COMPOSE_PROJECT_NAME)
HOST_SSHAGENT_NAME=$(read_or_default "SSH Agent container name" $DEFAULT_HOST_SSHAGENT_NAME)
HOST_SSHAGENT_HOST_MAP_FOLD_PATH=$(read_or_default "SSH Agent host map folder path" $DEFAULT_HOST_SSHAGENT_HOST_MAP_FOLD_PATH)
HOST_SSHAGENT_CONTAINER_MAP_FOLD_PATH=$(read_or_default "SSH Agent container map folder path" $DEFAULT_HOST_SSHAGENT_CONTAINER_MAP_FOLD_PATH)
HOST_MSSQL_NAME=$(read_or_default "Database container name" $DEFAULT_HOST_MSSQL_NAME)
HOST_MSSQL_PORT=$(read_or_default "Database container port" $DEFAULT_HOST_MSSQL_PORT)
HOST_MSSQL_PASSWORD=$(read_or_default "Database SA password" $DEFAULT_HOST_MSSQL_PASSWORD)
# Validate password complexity
while ! check_password_complexity "$HOST_MSSQL_PASSWORD" "SA"; do
    echo "Please enter a valid password. Password must be at least eight characters long and contain characters from at least three of the following categories: uppercase letters, lowercase letters, digits, special characters."
    HOST_MSSQL_PASSWORD=$(read_or_default "Database SA password" $DEFAULT_HOST_MSSQL_PASSWORD)
done
echo "Database SA password set successfully."
HOST_APP_NAME=$(read_or_default "App container name" $DEFAULT_HOST_APP_NAME)
HOST_APP_PORT=$(read_or_default "App container port" $DEFAULT_HOST_APP_PORT)
HOST_APP_HOST_MAP_FOLD_NAME=$(read_or_default "App host map folder name" $DEFAULT_HOST_APP_HOST_MAP_FOLD_NAME)
HOST_APP_CONTAINER_MAP_FOLD_PATH=$(read_or_default "App container map folder path" $DEFAULT_HOST_APP_CONTAINER_MAP_FOLD_PATH)
HOST_DATA_STAGING_NAME=$(read_or_default "Data Staging container name" $DEFAULT_HOST_DATA_STAGING_NAME)
HOST_DATA_STAGING_PORT=$(read_or_default "Data Staging container port" $DEFAULT_HOST_DATA_STAGING_PORT)
HOST_DATA_STAGING_HOST_MAP_FOLD_NAME=$(read_or_default "Data Staging host map folder name" $DEFAULT_HOST_DATA_STAGING_HOST_MAP_FOLD_NAME)
HOST_DATA_STAGING_CONTAINER_MAP_FOLD_PATH=$(read_or_default "Data Staging container map folder path" $DEFAULT_HOST_DATA_STAGING_CONTAINER_MAP_FOLD_PATH)

# Create .env file with newlines
cat <<EOF > .env
COMPOSE_PROJECT_NAME=$COMPOSE_PROJECT_NAME

HOST_SSHAGENT_NAME=$HOST_SSHAGENT_NAME
HOST_SSHAGENT_HOST_MAP_FOLD_PATH=$HOST_SSHAGENT_HOST_MAP_FOLD_PATH
HOST_SSHAGENT_CONTAINER_MAP_FOLD_PATH=$HOST_SSHAGENT_CONTAINER_MAP_FOLD_PATH

HOST_MSSQL_NAME=$HOST_MSSQL_NAME
HOST_MSSQL_PORT=$HOST_MSSQL_PORT
HOST_MSSQL_PASSWORD=$HOST_MSSQL_PASSWORD

HOST_APP_NAME=$HOST_APP_NAME
HOST_APP_PORT=$HOST_APP_PORT
HOST_APP_HOST_MAP_FOLD_NAME=$HOST_APP_HOST_MAP_FOLD_NAME
HOST_APP_CONTAINER_MAP_FOLD_PATH=$HOST_APP_CONTAINER_MAP_FOLD_PATH

HOST_DATA_STAGING_NAME=$HOST_DATA_STAGING_NAME
HOST_DATA_STAGING_PORT=$HOST_DATA_STAGING_PORT
HOST_DATA_STAGING_HOST_MAP_FOLD_NAME=$HOST_DATA_STAGING_HOST_MAP_FOLD_NAME
HOST_DATA_STAGING_CONTAINER_MAP_FOLD_PATH=$HOST_DATA_STAGING_CONTAINER_MAP_FOLD_PATH
EOF

echo ".env file created with the provided values."

# Create docker-compose.override.yml file
cat <<EOF > docker-compose.override.yml
version: '3.4'

services:
    sshagent:
        container_name: \${HOST_SSHAGENT_NAME}
        volumes:
            - \${HOST_SSHAGENT_HOST_MAP_FOLD_PATH}:\${HOST_SSHAGENT_CONTAINER_MAP_FOLD_PATH}

    mssql:
        container_name: \${HOST_MSSQL_NAME}
        environment:
            SA_PASSWORD: \${HOST_MSSQL_PASSWORD}
        ports:
            - \${HOST_MSSQL_PORT}:1433    

    heappe:
        container_name: \${HOST_APP_NAME}
        volumes:
            - \${HOST_APP_HOST_MAP_FOLD_NAME}:\${HOST_APP_CONTAINER_MAP_FOLD_PATH}
        ports:
            - \${HOST_APP_PORT}:80
        extra_hosts:
            - "host.docker.internal:host-gateway"

    datastagingapi:
        container_name: \${HOST_DATA_STAGING_NAME}
        volumes:
            - \${HOST_DATA_STAGING_HOST_MAP_FOLD_NAME}:\${HOST_DATA_STAGING_CONTAINER_MAP_FOLD_PATH}
        ports:
            - \${HOST_DATA_STAGING_PORT}:80
EOF

echo "docker-compose.override.yml file created with the provided values."

# Clone the HEAppE repository and copy the configuration files
cd "${BASE_PATH}/projects/${PROJECT_DIRECTORY}" || exit
git clone https://github.com/It4innovations/HEAppE.git heappe-core
cp docker_configurations/docker-compose.override.yml heappe-core/
cp docker_configurations/.env heappe-core/

echo "HEAppE repository cloned and configuration files copied."


# APPSETTINGS FILE
appsettings_file="${BASE_PATH}/projects/${PROJECT_DIRECTORY}/app/confs/appsettings.json"
cp "${BASE_PATH}/projects/${PROJECT_DIRECTORY}/heappe-core/RestApi/appsettings.example.json" "$appsettings_file"

MIDDLEWARE_CONTEXT="Server=mssql;Database=heappe;User=SA;Password=${HOST_MSSQL_PASSWORD};TrustServerCertificate=true;"
ESCAPED_MIDDLEWARE_CONTEXT=$(printf '%s\n' "$MIDDLEWARE_CONTEXT" | sed -e 's/[\/&]/\\&/g')
sed -i -E "s|\"MiddlewareContext\": \"[^\"]*\"|\"MiddlewareContext\": \"${ESCAPED_MIDDLEWARE_CONTEXT}\"|" "$appsettings_file"
# find "SharedAccountsPoolMode": false, and change to true
sed -i 's/"SharedAccountsPoolMode": false,/"SharedAccountsPoolMode": true,/' "$appsettings_file"
echo "appsettings.json configuration file is ready at ${BASE_PATH}/projects/${PROJECT_DIRECTORY}/app/confs/"


# APPSETTINGS-DATASTAGING FILE
appsettings_datastaging_file="${BASE_PATH}/projects/${PROJECT_DIRECTORY}/app/confs/appsettings-data.json"
cp "${BASE_PATH}/projects/${PROJECT_DIRECTORY}/heappe-core/DataStagingAPI/appsettings.example.json" "$appsettings_datastaging_file"
sed -i -E "s|\"MiddlewareContext\": \"[^\"]*\"|\"MiddlewareContext\": \"${ESCAPED_MIDDLEWARE_CONTEXT}\"|" "$appsettings_datastaging_file"
echo "appsettings-data.json configuration file is ready at ${BASE_PATH}/projects/${PROJECT_DIRECTORY}/app/confs/"



# SEED FILE
seed_file="${BASE_PATH}/projects/${PROJECT_DIRECTORY}/app/confs/seed.njson"
cp "${BASE_PATH}/projects/${PROJECT_DIRECTORY}/heappe-core/RestApi/seed.example.njson" "$seed_file"
sed -i 's/{UserName}/admin/g' "$seed_file"
sed -i 's/{Password}/FC6274073D28436E7D00F989D1D65A0C639D1D115FAC5A6B3D3C3F1316CECD7AD698105291617264D4DB6401AB17AB30D9A38784D6FC663A6414453A039803B9/g' "$seed_file"

sed -i 's/{GroupName}/Users/g' "$seed_file"
sed -i 's/{GroupDescription}/Default user group/g' "$seed_file"
sed -i 's/{OpenIDGroupDescription}/Default OpenID group/g' "$seed_file"

# {CreatedAt} to current date
sed -i "s/{CreatedAt}/$(date +'%Y-%m-%d %H:%M:%S')/" "$seed_file"
# "{MaxWalltime}"
sed -i 's/"{MaxWalltime}"/3600/g' "$seed_file"
# {StartDate}
sed -i "s/{StartDate}/$(date -d '-1 year' +'%Y-%m-%d %H:%M:%S')/" "$seed_file"
sed -i "s/{ValidityFrom}/$(date -d '-1 year' +'%Y-%m-%d %H:%M:%S')/" "$seed_file"
# {EndDate}
sed -i "s/{EndDate}/$(date -d '+1 year' +'%Y-%m-%d %H:%M:%S')/" "$seed_file"
sed -i "s/{ValidityTo}/$(date -d '+1 year' +'%Y-%m-%d %H:%M:%S')/" "$seed_file"

sed -i 's/"{NumberOfNodes}"/1/g' "$seed_file"
sed -i 's/"{CoresPerNode}"/1/g' "$seed_file"

echo "seed.njson configuration file is ready at ${BASE_PATH}/projects/${PROJECT_DIRECTORY}/app/confs/"

# Start HEAppE
echo "Starting HEAppE ..."
cd "${BASE_PATH}/projects/${PROJECT_DIRECTORY}/heappe-core" || exit
docker compose up -d --force-recreate
docker ps



exit 0