#!/bin/bash

# Support docker compose v1 and v2
shopt -s expand_aliases
alias docker-compose='docker compose'
if ! docker compose version &> /dev/null; then
    unalias docker-compose
fi

# Change default http timeout for slow networks
export COMPOSE_HTTP_TIMEOUT=500
export DOCKER_CLIENT_TIMEOUT=500

collect_basic_information() {
    LINUX_VERSION=$(lsb_release -d)
    DOCKER_PS=$(docker ps)
    DOCKER_VERSION=$(docker version --format '{{.Server.Version}}')
    DOCKER_COMPOSE_VERSION=$(docker-compose version --short)
    OV_FOLDER="${PWD}"
    OV_VERSION=$(grep 'Openvidu Version:' "${OV_FOLDER}/docker-compose.yml" | awk '{ print $4 }')
    CONTAINERS=$(docker ps | awk '{if(NR>1) print $NF}')
    if [ -n "$(grep -E '^        image: openvidu/openvidu-call:.*$' "${OV_FOLDER}/docker-compose.override.yml" | tr -d '[:space:]')" ]; then
        OV_CALL_VERSION=$(grep -E 'Openvidu-Call Version:' "${OV_FOLDER}/docker-compose.override.yml" | awk '{ print $4 }')
    fi
    [ -z "${OV_CALL_VERSION}" ] && OV_CALL_VERSION="No present"
    OV_TYPE_INSTALLATION=$(grep 'Installation Mode:' "${OV_FOLDER}/docker-compose.yml" | awk '{ print $4,$5 }')
    TREE_OV_DIRECTORY=$(find "." ! -path '*/0/*' | sed -e "s/[^-][^\/]*\// |/g" -e "s/|\([^ ]\)/|-\1/")
}

version_ov() {
    collect_basic_information

    printf '\nOpenvidu Information:'
    printf '\n'
    printf '\n  Openvidu Enterprise HA Base Services'
    printf '\n  Installation Type: %s' "${OV_TYPE_INSTALLATION}"
    printf '\n  Openvidu Version: %s' "${OV_VERSION}"
    printf '\n  Openvidu Call Version: %s' "${OV_CALL_VERSION}"
    printf '\n'
    printf '\nSystem Information:'
    printf '\n'
    printf '\n  Linux Version:'
    printf '\n    - %s' "${LINUX_VERSION}"
    printf '\n  Docker Version: %s' "${DOCKER_VERSION}"
    printf '\n  Docker Compose Version: %s' "${DOCKER_COMPOSE_VERSION}"
    printf '\n'
    printf '\nInstallation Information:'
    printf '\n'
    printf '\n  Installation Folder: %s' "${OV_FOLDER}"
    printf '\n  Installation Folder Tree:'
    printf '\n%s' "$(echo "${TREE_OV_DIRECTORY}" | sed -e 's/.//' -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')"
    printf '\n'
    printf '\nDocker Running Services:'
    printf '\n'
    printf '\n  %s' "$(echo "${DOCKER_PS}" | sed -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')"
    printf '\n'
}

generate_report() {
    collect_basic_information

    REPORT_CREATION_DATE=$(date +"%d-%m-%Y")
    REPORT_CREATION_TIME=$(date +"%H:%M:%S")
    REPORT_NAME="openvidu-report-${REPORT_CREATION_DATE}-$(date +"%H-%M").txt"
    REPORT_OUTPUT="${OV_FOLDER}/${REPORT_NAME}"

    {
        printf "\n  ======================================="
        printf "\n  =         REPORT INFORMATION          ="
        printf "\n  ======================================="
        printf '\n'
        printf '\n  Creation Date: %s' "${REPORT_CREATION_DATE}"
        printf '\n  Creation Time: %s' "${REPORT_CREATION_TIME}"
        printf '\n'
        printf "\n  ======================================="
        printf "\n  =       OPENVIDU INFORMATION          ="
        printf "\n  ======================================="
        printf '\n'
        printf '\n  Openvidu Enterprise HA Base Services'
        printf '\n  Installation Type: %s' "${OV_TYPE_INSTALLATION}"
        printf '\n  Openvidu Version: %s' "${OV_VERSION}"
        printf '\n  Openvidu Call Version: %s' "${OV_CALL_VERSION}"
        printf '\n'
        printf "\n  ======================================="
        printf "\n  =         SYSTEM INFORMATION          ="
        printf "\n  ======================================="
        printf '\n'
        printf '\n  Linux Version:'
        printf '\n    - %s' "${LINUX_VERSION}"
        printf '\n  Docker Version: %s' "${DOCKER_VERSION}"
        printf '\n  Docker Compose Version: %s' "${DOCKER_COMPOSE_VERSION}"
        printf '\n'
        printf "\n  ======================================="
        printf "\n  =     INSTALLATION INFORMATION        ="
        printf "\n  ======================================="
        printf '\n'
        printf '\n  Installation Folder: %s' "${OV_FOLDER}"
        printf '\n  Installation Folder Tree:'
        printf '\n%s' "$(echo "${TREE_OV_DIRECTORY}" | sed -e 's/.//' -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')"
        printf '\n'
        printf "\n  ======================================="
        printf "\n  =      DOCKER RUNNING SERVICES        ="
        printf "\n  ======================================="
        printf '\n'
        printf '\n  %s' "$(echo "${DOCKER_PS}" | sed -e ':a' -e 'N;$!ba' -e 's/\n/\n\t/g')"
        printf '\n'
        printf "\n  ======================================="
        printf "\n  =        CONFIGURATION FILES          ="
        printf "\n  ======================================="
        printf '\n'
        printf '\n  ================ .env ================='
        printf '\n'
        printf '\n'

        cat < "${OV_FOLDER}/.env" | sed -r -e "s/OPENVIDU_SECRET=.+/OPENVIDU_SECRET=****/" -e "s/OPENVIDU_PRO_LICENSE=.+/OPENVIDU_PRO_LICENSE=****/" -e "s/ELASTICSEARCH_PASSWORD=.+/ELASTICSEARCH_PASSWORD=****/"

        printf '\n'
        printf '\n  ========= docker-compose.yml =========='
        printf '\n'
        printf '\n'

        cat "${OV_FOLDER}/docker-compose.yml"

        printf '\n'
        printf '\n  ==== docker-compose.override.yml ===='
        printf '\n'
        printf '\n'

        if [ -f "${OV_FOLDER}/docker-compose.override.yml" ]; then
            cat < "${OV_FOLDER}/docker-compose.override.yml"
        else
            printf '\n  The docker-compose.override.yml file is not present'
        fi

        printf '\n'
        printf '\n'
        printf "\n  ======================================="
        printf "\n  =                LOGS                 ="
        printf "\n  ======================================="

        for CONTAINER in $CONTAINERS
        do
            printf '\n'
            printf "\n  ---------------------------------------"
            printf "\n  %s" "$CONTAINER"
            printf "\n  ---------------------------------------"
            printf '\n'
            docker logs "$CONTAINER"
            printf "\n  ---------------------------------------"
            printf '\n'
            printf '\n'
        done

        printf "\n  ======================================="
        printf "\n  =       CONTAINER ENVS VARIABLES      ="
        printf "\n  ======================================="

        for CONTAINER in $CONTAINERS
        do
            printf '\n'
            printf "\n  ======================================="
            printf "\n  %s" "$CONTAINER"
            printf "\n  ---------------------------------------"
            printf '\n'
            docker exec "$CONTAINER" env
            printf "\n  ---------------------------------------"
            printf '\n'
            printf '\n'
        done

    } >> "${REPORT_OUTPUT}" 2>&1

    printf "\n  Generation of the report completed with success"
    printf "\n  You can get your report at path '%s'" "${REPORT_OUTPUT}"
    printf "\n"
}

print_env_error() {
    printf "\n     =======¡ERROR!======="
    printf "\n  ERROR: You must set the '%s' variable in the .env file" "${1}"
    printf "\n"
}

check_non_empty_parameters() {
    local NON_EMPTY_ENV_VARS=("$@")
    for ENV_VAR_NAME in "${NON_EMPTY_ENV_VARS[@]}" ; do
        ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2)
        if [[ -z "${ENV_VAR_VALUE}" ]]; then
            print_env_error "${ENV_VAR_NAME}"
            exit 1
        fi
    done
}

get_env_var_value() {
    local ENV_VAR_NAME=$1
    local ENV_VAR_VALUE
    ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2)
    echo "${ENV_VAR_VALUE}"
}

check_env_var_is_value() {
    local ENV_VAR_NAME=$1
    local ENV_VAR_VALUE=$2
    local ENV_VAR_VALUE_TO_CHECK
    ENV_VAR_VALUE_TO_CHECK=$(get_env_var_value "${ENV_VAR_NAME}")
    if [[ "${ENV_VAR_VALUE_TO_CHECK}" != "${ENV_VAR_VALUE}" ]]; then
        print_env_error "${ENV_VAR_NAME}"
        exit 1
    fi
}

print_env_error() {
    printf "\n     =======¡ERROR!======="
    printf "\n     %s" "$1"
    printf "\n"
}

check_non_empty_parameters() {
    local NON_EMPTY_ENV_VARS=("$@")
    for ENV_VAR_NAME in "${NON_EMPTY_ENV_VARS[@]}" ; do
        ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2)
        if [[ -z "${ENV_VAR_VALUE}" ]]; then
            ERRORS+=("ERROR: You must set the '${ENV_VAR_NAME}' variable in the .env file")
        fi
    done
}

get_env_var_value() {
    local ENV_VAR_NAME=$1
    local ENV_VAR_VALUE
    ENV_VAR_VALUE=$(grep -v '^#' .env | grep "${ENV_VAR_NAME}" | cut -d '=' -f2)
    echo "${ENV_VAR_VALUE}"
}

validate_env_vars() {
    ERRORS=()
    check_non_empty_parameters "DOMAIN_OR_PUBLIC_IP" \
        "OPENVIDU_SECRET" \
        "CERTIFICATE_TYPE" \
        "OPENVIDU_ENTERPRISE_HA_NODE_IPS" \
        "OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD" \
        "OPENVIDU_ENTERPRISE_HA_S3_CONFIG_BUCKET" \
        "OPENVIDU_ENTERPRISE_HA_S3_CONFIG_ACCESS_KEY" \
        "OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY" \
        "ELASTICSEARCH_USERNAME" \
        "ELASTICSEARCH_PASSWORD"

    local OPENVIDU_SECRET
    OPENVIDU_SECRET=$(get_env_var_value "OPENVIDU_SECRET")
    if [[ ! "${OPENVIDU_SECRET}" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        ERRORS+=("OPENVIDU_SECRET: Value must be alphanumeric and can include '-' or '_'.")
    fi

    local CERTIFICATE_TYPE
    CERTIFICATE_TYPE=$(get_env_var_value "CERTIFICATE_TYPE")
    if [[ "${CERTIFICATE_TYPE}" == "letsencrypt" ]]; then
        local LETSENCRYPT_EMAIL
        LETSENCRYPT_EMAIL=$(get_env_var_value "LETSENCRYPT_EMAIL")
        if [[ -z "${LETSENCRYPT_EMAIL}" ]]; then
            ERRORS+=("LETSENCRYPT_EMAIL: Value must not be empty when CERTIFICATE_TYPE is 'letsencrypt'.")
        fi
    fi

    local OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD
    OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD=$(get_env_var_value "OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD")
    if [[ ! "${OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD}" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        ERRORS+=("OPENVIDU_ENTERPRISE_HA_REDIS_PASSWORD: Value must be alphanumeric and can include '-' or '_'.")
    fi

    local OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY
    OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY=$(get_env_var_value "OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY")
    if [[ ! "${OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY}" =~ ^[a-zA-Z0-9_-]+$ ]]; then
        ERRORS+=("OPENVIDU_ENTERPRISE_HA_S3_CONFIG_SECRET_KEY: Value must be alphanumeric and can include '-' or '_'.")
    fi

    local ELASTICSEARCH_PASSWORD
    ELASTICSEARCH_PASSWORD=$(get_env_var_value "ELASTICSEARCH_PASSWORD")
    if [[ ! "${ELASTICSEARCH_PASSWORD}" =~ ^[a-zA-Z0-9_-]{7,}$ ]]; then
        ERRORS+=("ELASTICSEARCH_PASSWORD: Value must be alphanumeric (and can include '-' or '_') with a minimum length of 7.")
    fi

    if [[ ${#ERRORS[@]} -ne 0 ]]; then
        for error in "${ERRORS[@]}"; do
            print_env_error "${error}"
        done
        exit 1
    fi
}

start_openvidu() {
    docker-compose up -d
}

usage() {
    printf "Usage: \n\t base-services [command]"
    printf "\n\nAvailable Commands:"
    printf "\n\tstart\t\t\tStart all services"
    printf "\n\tstop\t\t\tStop all services"
    printf "\n\trestart\t\t\tRestart all stopped and running services"
    printf "\n\tupdate-loadbalancer\tUpdate load balancer IPs \n\t\t\t\tfrom OPENVIDU_ENTERPRISE_HA_NODE_IPS"
    printf "\n\tlogs\t\t\tShow openvidu-server logs"
    printf "\n\tupgrade\t\t\tUpgrade to the latest Openvidu version"
    printf "\n\tupgrade [version]\tUpgrade to the specific Openvidu version"
    printf "\n\tversion\t\t\tShow version of Openvidu Server"
    printf "\n\treport\t\t\tGenerate a report with the current status of Openvidu"
    printf "\n\thelp\t\t\tShow help for openvidu command"
    printf "\n"
}

[[ -z "${FOLLOW_OPENVIDU_LOGS}" ]] && FOLLOW_OPENVIDU_LOGS=true

case $1 in

start)
    validate_env_vars
    start_openvidu
    if [[ "${FOLLOW_OPENVIDU_LOGS}" == "true" ]]; then
        # Docker compose logs of openvidu-server and repliation-manager containers
        docker-compose logs -f --tail 10
    fi
;;

stop)
    docker-compose down
;;

restart)
    validate_env_vars
    docker-compose down
    start_openvidu
    if [[ "${FOLLOW_OPENVIDU_LOGS}" == "true" ]]; then
        docker-compose logs -f --tail 10
    fi
;;

update-loadbalancer)
    validate_env_vars
    OPENVIDU_ENTERPRISE_HA_NODE_IPS=$(get_env_var_value "OPENVIDU_ENTERPRISE_HA_NODE_IPS")
    docker-compose exec -it \
        -e OPENVIDU_ENTERPRISE_HA_NODE_IPS="${OPENVIDU_ENTERPRISE_HA_NODE_IPS}" \
        loadbalancer update_enterprise_ha_nodes.sh
;;

logs)
    case "${2-}" in
        --follow|-f)
            docker-compose logs -f --tail 10
        ;;

        *)
            docker-compose logs
        ;;
    esac
;;

version)
    version_ov
;;

report)
    read -r -p "  You are about to generate a report on the current status of Openvidu, this may take some time. Do you want to continue? [y/N]: " response
    case "$response" in
        [yY][eE][sS]|[yY])
            generate_report
        ;;

        *)
            exit 0
        ;;
    esac
;;

*)
    usage
;;
esac
