#!/bin/sh
# scripts/aws/run_aws.sh
# 2023-02-02 | CR
#
check_chalice_framework() {
    if [[ "${CURRENT_FRAMEWORK}" != "chalice" && "${CURRENT_FRAMEWORK}" != "chalice_docker" ]]; then
        echo "CURRENT_FRAMEWORK '${CURRENT_FRAMEWORK}' doesn't need 'set_chalice_cnf.sh' script to run [2]..."
        exit 0
    fi
    echo "bash ${SCRIPTS_DIR}/set_chalice_cnf.sh ${STAGE}" http
    bash ${SCRIPTS_DIR}/set_chalice_cnf.sh ${STAGE} http
}

set_chalice_autoreload_option() {
    if [ "${AUTO_RELOAD}" = "0" ]; then
        AUTO_RELOAD_OPTION="--no-autoreload"
    elif [ "${AUTO_RELOAD}" = "-" ]; then
        AUTO_RELOAD_OPTION=""
    else
        AUTO_RELOAD_OPTION="--autoreload"
    fi
    export AUTO_RELOAD_OPTION
}

set_generic_autoreload_option() {
    if [ "${AUTO_RELOAD}" = "0" ]; then
        AUTO_RELOAD_OPTION=""
    else
        AUTO_RELOAD_OPTION="--reload"
    fi
    export AUTO_RELOAD_OPTION
}

set_gunicorn_autoreload_option() {
    set_generic_autoreload_option
}

set_uvicorn_autoreload_option() {
    set_generic_autoreload_option
}

PEM_TOOL="uv"

REPO_BASEDIR="`pwd`"
cd "`dirname "$0"`"
SCRIPTS_DIR="`pwd`"
cd "${REPO_BASEDIR}"

set -o allexport ; . .env ; set +o allexport ;
. ${SCRIPTS_DIR}/../set_app_dir_and_main_file.sh

if [ "${APP_NAME}" = "" ]; then
    echo "APP_NAME not set"
    exit 1
fi

if [ "${CURRENT_FRAMEWORK}" = "" ]; then
    echo "CURRENT_FRAMEWORK not set"
    exit 1
fi

if [ "${APP_DOMAIN_NAME}" = "" ]; then
    echo "ERROR: APP_HOST_NAME not set"
    exit 1
fi

if [ "${STORAGE_URL_SEED}" = "" ]; then
    if [ "${STORAGE_URL_ENCRYPTION}" = "1" ]; then
        echo "ERROR: STORAGE_URL_ENCRYPTION is set to 1 but STORAGE_URL_SEED is not set"
        exit 1
    fi
fi

if [ ! -d "./${APP_DIR}" ]; then
  echo "ERROR: APP_DIR './${APP_DIR}' not found"
  exit 1
fi

if [ ! -f "${APP_DIR}/${APP_MAIN_FILE}.py" ]; then
  echo "ERROR: APP_DIR/APP_MAIN_FILE '"${APP_DIR}/${APP_MAIN_FILE}".py' not found"
  exit 1
fi

export APP_NAME_LOWERCASE=$(echo ${APP_NAME} | tr '[:upper:]' '[:lower:]')

AWS_STACK_NAME="${APP_NAME_LOWERCASE}-be-stack"

# Default RUN_METHOD:
# RUN_METHOD="uvicorn"
# RUN_METHOD="gunicorn"
# RUN_METHOD="chalice"
RUN_METHOD="chalice_docker"

# Run protocol and port replacement: automatic protocol and port replacement for
# local development environment variables REACT_APP_API_URL and APP_API_URL
# when RUN_PROTOCOL="https" can be turned off by assigning RUN_PROTOCOL_AND_PORT_REPLACEMENT=0.
# Defaults to "1"
RUN_PROTOCOL_AND_PORT_REPLACEMENT=1

# Whether to use containers engine app for local development environment when RUN_PROTOCOL="https". Defaults to "1"
USE_CONTAINERS_ENGINE_APP=1

echo "SCRIPTS_DIR: ${SCRIPTS_DIR}"
echo "REPO_BASEDIR: ${REPO_BASEDIR}"

ENV_FILESPEC=""
if [ -f "${REPO_BASEDIR}/.env" ]; then
    ENV_FILESPEC="${REPO_BASEDIR}/.env"
fi
if [ "$ENV_FILESPEC" != "" ]; then
    set -o allexport; source ${ENV_FILESPEC}; set +o allexport ;
fi

if [ "$BACKEND_LOCAL_PORT" = "" ]; then
    BACKEND_LOCAL_PORT="5001"
fi

if [ "$2" = "" ]; then
    STAGE="dev"
else
    STAGE="$2"
fi
STAGE_UPPERCASE=$(echo $STAGE | tr '[:lower:]' '[:upper:]')

if [ "$1" = "shell" ]; then
	bash ${SCRIPTS_DIR}/../run_pem.sh shell
fi

if [ "$1" = "pipfile" ]; then
	bash ${SCRIPTS_DIR}/../run_pem.sh requirements
fi

if [ "$1" = "requirements" ]; then
	bash ${SCRIPTS_DIR}/../run_pem.sh requirements
fi

if [ "$1" = "clean" ]; then
    echo "Cleaning..."
    if [ "${APP_DIR}" = "." ]; then
        if [ -d "${REPO_BASEDIR}/lib" ]; then
            cd ${REPO_BASEDIR}/lib
        else
            cd ${REPO_BASEDIR}/chalicelib ;
        fi
    fi
    deactivate ;
    rm -rf __pycache__ ;
    rm -rf ../__pycache__ ;
    rm -rf bin ;
    # rm -rf include ;
    # rm -rf instance ;
    # rm -rf lib ;
    # rm -rf src ;
    rm -rf pyvenv.cfg ;
    rm -rf .vercel/cache ;
    rm -rf ../.vercel/cache ;
    rm -rf ../node_modules ;
    # rm requirements.txt
    # rm ../requirements.txt
    # rm -rf var ;
    ls -lah
fi

if [[ "$1" = "test" ]]; then
    echo "Run test..."
    python -m pytest
    echo "Done..."
fi

if [[ "$1" = "run_local" || "$1" = "" ]]; then
    # Run FastAPI, Flask or Chalice
    cd ${REPO_BASEDIR}

    echo ""
    echo "Stage: ${STAGE}"
    echo "Port: ${BACKEND_LOCAL_PORT}"
    echo "Run method (RUN_METHOD): ${RUN_METHOD}"
    echo "Run protocol (RUN_PROTOCOL): ${RUN_PROTOCOL}"
    echo "Run protocol and port replacement (RUN_PROTOCOL_AND_PORT_REPLACEMENT): ${RUN_PROTOCOL_AND_PORT_REPLACEMENT}"
    echo "Use containers engine app (USE_CONTAINERS_ENGINE_APP): ${USE_CONTAINERS_ENGINE_APP}"
    echo "Python entry point (APP_DIR.APP_MAIN_FILE): ${APP_DIR}.${APP_MAIN_FILE}"
    echo ""

    export IP_ADDRESS=$(bash ${SCRIPTS_DIR}/../get_localhost_ip.sh)
    export APP_VERSION=$(cat ${REPO_BASEDIR}/version.txt)

    if [ "${RUN_PROTOCOL}" = "" ]; then
        echo "Run over: 1) http, 2) https ?"
        read RUN_PROTOCOL
        while [[ ! ${RUN_PROTOCOL} =~ ^[12]$ ]]; do
            echo "Please enter 1 or 2"
            read RUN_PROTOCOL
        done
        if [ "${RUN_PROTOCOL}" = "1" ]; then
            export RUN_PROTOCOL="http"
        else
            export RUN_PROTOCOL="https"
        fi
    elif [ "${RUN_PROTOCOL}" != "http" ]; then
        if [ "${RUN_PROTOCOL}" != "https" ]; then
            echo "ERROR: Invalid run protocol: ${RUN_PROTOCOL}"
            exit 1
        fi
    fi

    if [ "${STAGE}" = "dev" ];then
        . ${SCRIPTS_DIR}/../get_domain_name_dev.sh "${STAGE}" "${APP_DOMAIN_NAME}" "${SCRIPTS_DIR}/.." "${USE_CONTAINERS_ENGINE_APP}"
        export GS_LOCAL_ENVIR="true"
    else
        . ${SCRIPTS_DIR}/../get_domain_name.sh "${STAGE}"
    fi
    if [ "${DOMAIN_NAME}" = "" ];then
        exit 1
    fi
    export APP_HOST_NAME="${DOMAIN_NAME}"

    export APP_DB_ENGINE=$(eval echo \$APP_DB_ENGINE_${STAGE_UPPERCASE})
    export APP_DB_NAME=$(eval echo \$APP_DB_NAME_${STAGE_UPPERCASE})
    if [[ "${GET_SECRETS_ENABLED}" = "0" || "${GET_SECRETS_CRITICAL}" = "0" ]]; then
        export APP_DB_URI=$(eval echo \$APP_DB_URI_${STAGE_UPPERCASE})
    fi
    export APP_CORS_ORIGIN="$(eval echo \"\$APP_CORS_ORIGIN_${STAGE_UPPERCASE}\")"
    export AWS_S3_CHATBOT_ATTACHMENTS_BUCKET=$(eval echo \$AWS_S3_CHATBOT_ATTACHMENTS_BUCKET_${STAGE_UPPERCASE})

    if [ "${CURRENT_FRAMEWORK}" = "chalice" ]; then
        if [ "${RUN_PROTOCOL}" = "https" ] && [ "${USE_CONTAINERS_ENGINE_APP}" = "1" ]; then
            export RUN_METHOD="chalice_docker"
        else
            export RUN_METHOD="chalice"
            make down_qa
        fi
    else
        if [ "${RUN_PROTOCOL}" = "http" ]; then
            make down_qa

            if [ "${RUN_PROTOCOL_AND_PORT_REPLACEMENT}" = "1" ]; then
                echo "NOTE: The warning '-i used with no filenames on the command line, reading from STDIN.' is normal..."
                echo ">> Old APP_CORS_ORIGIN: ${APP_CORS_ORIGIN}"
                if [ "${APP_CORS_ORIGIN}" != "*" ]; then
                    export APP_CORS_ORIGIN="$(echo ${APP_CORS_ORIGIN} | perl -i -pe 's|https:\/\/|http:\/\/|')"
                fi
                echo ">> New APP_CORS_ORIGIN: ${APP_CORS_ORIGIN}"
            else
                echo ">> APP_CORS_ORIGIN: ${APP_CORS_ORIGIN}"
            fi
        fi
    fi

    export APP_STAGE="${STAGE}"
    # To avoid message from langsmith:
    # USER_AGENT environment variable not set, consider setting it to identify your requests.
    export USER_AGENT="${APP_NAME_LOWERCASE}-${STAGE}"

    export DYNAMDB_PREFIX=$(eval echo \$DYNAMDB_PREFIX_${STAGE_UPPERCASE})
    if [ "${DYNAMDB_PREFIX}" = "" ]; then
        export DYNAMDB_PREFIX="${APP_NAME_LOWERCASE}_${STAGE}_"
    fi

    echo ""
    echo "APP_STAGE: ${APP_STAGE}"
    echo "USER_AGENT: ${USER_AGENT}"

    if [ "${RUN_METHOD}" = "chalice" ]; then
        set_chalice_autoreload_option
        check_chalice_framework
        echo ""
        echo "${PEM_TOOL} run chalice local --host 0.0.0.0 --port ${BACKEND_LOCAL_PORT} --stage ${STAGE} ${AUTO_RELOAD_OPTION}"
        echo ""
        ${PEM_TOOL} run chalice local --host 0.0.0.0 --port ${BACKEND_LOCAL_PORT} --stage ${STAGE} ${AUTO_RELOAD_OPTION}
    fi

    if [ "${RUN_METHOD}" = "chalice_docker" ]; then
        set_chalice_autoreload_option
        echo "${SCRIPTS_DIR}/../secure_local_server/run.sh"
        ${SCRIPTS_DIR}/../secure_local_server/run.sh "run" ${STAGE}
    fi

    if [ "${RUN_METHOD}" = "gunicorn" ]; then
        set_gunicorn_autoreload_option
        if [ "${RUN_PROTOCOL}" = "https" ] && [ "${USE_CONTAINERS_ENGINE_APP}" = "1" ]; then
            echo "${SCRIPTS_DIR}/../secure_local_server/run.sh"
            ${SCRIPTS_DIR}/../secure_local_server/run.sh "run" ${STAGE}
        else
            echo "${PEM_TOOL} run gunicorn --bind 0.0.0.0:${BACKEND_LOCAL_PORT} ${APP_DIR}.${APP_MAIN_FILE}:app ${AUTO_RELOAD_OPTION}  --forwarded-allow-ips=${IP_ADDRESS}"
            echo ""
            ${PEM_TOOL} run gunicorn ${APP_DIR}.${APP_MAIN_FILE}:app \
                --bind 0.0.0.0:${BACKEND_LOCAL_PORT} \
                ${AUTO_RELOAD_OPTION} \
                --workers=2 \
                --proxy-protocol \
                --limit-request-field_size=200000 \
                --forwarded-allow-ips="${IP_ADDRESS},127.0.0.1,0.0.0.0" \
                --do-handshake-on-connect \
                --strip-header-spaces \
                --log-level debug \
                --env PORT=${BACKEND_LOCAL_PORT} \
                --env APP_STAGE="${APP_STAGE}"
        fi
    fi

    if [ "${RUN_METHOD}" = "uvicorn" ]; then
        set_uvicorn_autoreload_option
        if [ "${PATH_TO_SAVE_OPENAPI}" != "" ]; then
            echo ""
            echo "Generating the OpenAPI schema files..."
            echo ""
            # Run uvicorn in background and terminate it if it is already running
            echo "Running: ${PEM_TOOL} run uvicorn ${APP_DIR}.${APP_MAIN_FILE}:app ${AUTO_RELOAD_OPTION} --host 0.0.0.0 --port ${BACKEND_LOCAL_PORT} --proxy-headers --forwarded-allow-ips=\"*\""
            
            # nohup ${PEM_TOOL} run uvicorn ${APP_DIR}.${APP_MAIN_FILE}:app ${AUTO_RELOAD_OPTION} --host 0.0.0.0 --port ${BACKEND_LOCAL_PORT} > /dev/null 2>&1 &
            ${PEM_TOOL} run uvicorn ${APP_DIR}.${APP_MAIN_FILE}:app ${AUTO_RELOAD_OPTION} --host 0.0.0.0 --port ${BACKEND_LOCAL_PORT} --proxy-headers --forwarded-allow-ips="*" &
            UVICORN_PID=$!
            
            echo "Waiting for the server (PID: ${UVICORN_PID}) to start..."
            for i in {1..30}; do
                # Assuming /docs is your OpenAPI UI endpoint, which is common for FastAPI.
                # Adjust if your health check endpoint is different.
                if curl -s --head "http://localhost:${BACKEND_LOCAL_PORT}/docs" | head -n 1 | grep "HTTP/1.[1-9] [23].." > /dev/null; then
                    echo "Server is up!"
                    # Here you would have the logic to fetch and save the OpenAPI schema.
                    # For example: curl http://localhost:${BACKEND_LOCAL_PORT}/openapi.json > ${PATH_TO_SAVE_OPENAPI}/openapi.json
                    break
                fi
                echo "Waiting for server... attempt $i"
                sleep 1
            done

            echo "Stopping the process: ${UVICORN_PID}"
            kill ${UVICORN_PID}
            wait ${UVICORN_PID} 2>/dev/null # Wait for the process to terminate
            echo ""
        else
            if [ "${RUN_PROTOCOL}" = "https" ] && [ "${USE_CONTAINERS_ENGINE_APP}" = "1" ]; then
                echo "${SCRIPTS_DIR}/../secure_local_server/run.sh"
                ${SCRIPTS_DIR}/../secure_local_server/run.sh "run" ${STAGE}
            else
                echo "${PEM_TOOL} run uvicorn ${APP_DIR}.${APP_MAIN_FILE}:app ${AUTO_RELOAD_OPTION} --host 0.0.0.0 --port ${BACKEND_LOCAL_PORT} --proxy-headers --forwarded-allow-ips=\"*\""
                echo ""
                ${PEM_TOOL} run uvicorn ${APP_DIR}.${APP_MAIN_FILE}:app ${AUTO_RELOAD_OPTION} --host 0.0.0.0 --port ${BACKEND_LOCAL_PORT} --proxy-headers --forwarded-allow-ips="*"
            fi
        fi
    fi

    # Stop local NGINX
    if [ "${STAGE}" = "dev" ];then
        bash ${SCRIPTS_DIR}/../get_domain_name_dev.sh "stop_local_nginx" "${APP_DOMAIN_NAME}" "${SCRIPTS_DIR}/.." "${USE_CONTAINERS_ENGINE_APP}"
    fi
fi

if [ "$1" = "run" ]; then
    # Run Chalice
    check_chalice_framework
    cd ${REPO_BASEDIR}
    echo ""
    echo "PRODUCCION RUNNING: ${PEM_TOOL} run chalice local --port ${BACKEND_LOCAL_PORT} --stage PROD"
    echo ""
    ${PEM_TOOL} run chalice local --host 0.0.0.0 --port ${BACKEND_LOCAL_PORT} --stage prod
fi

if [ "$1" = "deploy" ]; then
    check_chalice_framework
    # This must be run first (and it's run by "make"):
    #    make requirements
    cd ${REPO_BASEDIR}
    ${PEM_TOOL} run chalice package .chalice/deployment
    ${PEM_TOOL} run chalice deploy --stage ${STAGE}
    if [ "${STAGE}" = "qa" ]; then
        perl -i -pe "s|APP_CORS_ORIGIN_QA=.*|APP_CORS_ORIGIN_QA=${APP_CORS_ORIGIN_QA_LOCAL}|g" "${ENV_FILESPEC}"
    fi
fi

if [ "$1" = "create_stack" ]; then
    check_chalice_framework
    echo "Running: aws cloudformation deploy --template-file \"${REPO_BASEDIR}/.chalice/dynamodb_cf_template.yaml\" --stack-name \"${AWS_STACK_NAME}\""
    aws cloudformation deploy --template-file "${REPO_BASEDIR}/.chalice/dynamodb_cf_template.yaml" --stack-name "${AWS_STACK_NAME}"
fi

if [ "$1" = "describe_stack" ]; then
    check_chalice_framework
    echo "Running: aws cloudformation describe-stack-events --stack-name \"${AWS_STACK_NAME}\""
    aws cloudformation describe-stack-events --stack-name "${AWS_STACK_NAME}"
fi

if [ "$1" = "delete_app" ]; then
    # Delete application
    check_chalice_framework
    cd ${REPO_BASEDIR}
    echo "Running: ${PEM_TOOL} run chalice delete --stage ${STAGE}"
    ${PEM_TOOL} run chalice delete --stage ${STAGE}
fi

if [ "$1" = "delete_stack" ]; then
    # Delete DynamoDb tables
    check_chalice_framework
    echo "Running: aws cloudformation delete-stack --stack-name \"${AWS_STACK_NAME}\""
    aws cloudformation delete-stack --stack-name "${AWS_STACK_NAME}"
fi
