#!/usr/bin/env bash

os=`uname`

COMPOSE_BINARY=$(docker compose > /dev/null 2>&1 && echo "docker compose" || echo "docker-compose")

install (){
    [ -f .env ] && grep -q "GMS_MIRO_DATABASE_PWD" .env || {
        local db_password=$(LC_ALL=C tr -dc 'A-Za-z0-9' </dev/urandom | head -c 40 ; echo)
        printf "A new master password for your MIRO Server database was generated: ${db_password}\nPlease keep this password in a safe place.\n"
        printf "GMS_MIRO_DATABASE_PWD=${db_password}\n" > .env
    }
    if ! grep -q "GMS_MIRO_ENGINE_HOST" .env; then
        read -p 'Please enter GAMS Engine host: ' ENGINE_HOST
        [ -z ${ENGINE_HOST} ] && {
            echo "Invalid GAMS Engine host!"
            exit 1
        }
        echo "GMS_MIRO_ENGINE_HOST=${ENGINE_HOST}">>.env
    fi
    if ! grep -q "GMS_MIRO_ENGINE_NS" .env; then
        read -p 'Please specify the namespace to be connected to MIRO Server: ' ENGINE_NS
        [ -z ${ENGINE_NS} ] && {
            echo "Invalid GAMS Engine namespace!"
            exit 1
        }
        echo "GMS_MIRO_ENGINE_NS=${ENGINE_NS}">>.env
    fi

    printf "You can change the GAMS Engine connection info at any time by modifying the \".env\" file.\nNote that MIRO Server must be restarted for these changes to take effect.\n"

    read -p 'Enable authentication? [Y/n]: ' ENABLE_AUTH

    case "$ENABLE_AUTH" in
        [nN][oO]|[nN])
            sed -i -E "s/authentication: .*/authentication: none/" data_raw/application.yml || {
                echo "Problems updating authentication method."
                exit 1
            }
            if ! grep -q "GMS_MIRO_ENGINE_ANONYMOUS_USER" .env; then
                read -p 'Please enter name of user to be used to run jobs: ' ENGINE_ANON_USR
                [ -z ${ENGINE_ANON_USR} ] && {
                    echo "Invalid username!"
                    exit 1
                }
                echo "GMS_MIRO_ENGINE_ANONYMOUS_USER=${ENGINE_ANON_USR}">>.env
            fi
            if ! grep -q "GMS_MIRO_ENGINE_ANONYMOUS_PWD" .env; then
                read -sp 'Please enter password of this user: ' ENGINE_ANON_PWD
                [ -z ${ENGINE_ANON_PWD} ] && {
                    echo "Invalid password!"
                    exit 1
                }
                echo "GMS_MIRO_ENGINE_ANONYMOUS_PWD=${ENGINE_ANON_PWD}">>.env
            fi
            ;;
        *)
            sed -i -E "s/authentication: .*/authentication: webservice/" data_raw/application.yml || {
                echo "Problems updating authentication method."
                exit 1
            }
            ;;
    esac

    CURRENT_DIR_NAME=${PWD##*/}
    MIRO_SERVER_NETWORK_NAME="${CURRENT_DIR_NAME}-network"

    sed -i -E "s/container-network: .*/container-network: ${MIRO_SERVER_NETWORK_NAME}/" data_raw/application.yml || {
        echo "Problems updating container network in data_raw/application.yml."
        exit 1
    }
    sed -i -E "/gamsmiro-network:/{n;s/name:.*/name: ${MIRO_SERVER_NETWORK_NAME}/}" docker-compose.yml || {
        echo "Problems updating container network in docker-compose.yml."
        exit 1
    }

    printf "Installing GAMS MIRO Server. Please wait...\n\n\n"

    pull_images

    [ -d ./logs ] || mkdir logs
    if [ "$os" != "Darwin" ]; then
        chown -R 1000:1000 logs || {
            echo "Could not change ownership of directory \"logs\". Check your permissions."
            exit 1
        }
    fi

    [ -d ./data ] || mkdir data
    cp -a data_raw/. data/ || {
        echo "Failed to copy data files from \"data_raw\" to \"data\". Check your permissions."
        exit 1
    }
    if [ "$os" != "Darwin" ]; then
        chown -R 1000:1000 data || {
            echo "Could not change ownership of directory \"data\". Check your permissions."
            exit 1
        }
    fi

    [ -d ./models ] || mkdir models
    if [ "$os" != "Darwin" ]; then
        chown -R 1000:1000 models || {
            echo "Could not change ownership of directory \"models\". Check your permissions."
            exit 1
        }
    fi

    printf "GAMS MIRO Server installed successfully!\nUse './miro-server start' to start now.\n"
    return 0
}

build (){
    echo "Building custom MIRO Docker image"
    docker build --progress=plain -t gams/miro-ui:latest -f Dockerfile-extend-miro .
}

pull_images (){
    echo "Pulling Docker images for GAMS MIRO Server"
    $COMPOSE_BINARY -f docker-compose.yml pull || exit 1
}

update (){
    echo "Updating GAMS MIRO Server"
    BUILD_UI_IMAGE=false
    if grep -q '[^[:space:]]' ./additional_packages; then
        read -p 'It looks like you are using a custom MIRO image with additional packages. Do you want to recreate this image as part of the update? [Y/n]: ' REBUILD_UI_IMAGE

        case "$REBUILD_UI_IMAGE" in
            [nN][oO]|[nN])
                BUILD_UI_IMAGE=false
                ;;
            *)
                BUILD_UI_IMAGE=true
                ;;
        esac
    fi
    pull_images
    if [ "$BUILD_UI_IMAGE" = true ] ; then
        build
    fi
    start
}

start (){
    echo "Starting GAMS MIRO Server"
    $COMPOSE_BINARY -f docker-compose.yml up -d || exit 1
    echo "GAMS MIRO Server started."
}

stop_proxies (){
    local orphaned_adminc=$(docker container ls -f "network=miroserver-network" -f "ancestor=gams/miro-admin" --format "{{.ID}}")
    [ -z "${orphaned_adminc}" ] || {
        docker stop ${orphaned_adminc}
        docker rm ${orphaned_adminc}
    }

    local orphaned_uic=$(docker container ls -f "network=miroserver-network" -f "ancestor=gams/miro-ui" --format "{{.ID}}")
    [ -z "${orphaned_uic}" ] || {
        docker stop ${orphaned_uic}
        docker rm ${orphaned_uic}
    }
}

stop (){
    echo "Stopping GAMS MIRO Server"
    stop_proxies
    $COMPOSE_BINARY -f docker-compose.yml down || exit 1
    echo "GAMS MIRO Server stopped."
}

restart (){
    echo -e "Restarting GAMS MIRO Server.\n\nPlease note that changes to the 'docker-compose.yml' file or the '.env' file are not applied.\nRun './miro-server stop' and './miro-server start' instead!"
    export COMPOSE_IGNORE_ORPHANS=True
    $COMPOSE_BINARY -f docker-compose.yml restart || exit 1
    echo "GAMS MIRO Server restarted."
}

uninstall (){
    echo "Uninstalling GAMS MIRO Server"
    read -p 'Are you sure you want to remove all data of GAMS MIRO Server? This cannot be undone! (yes)' uninstall_confirm
    [ "${uninstall_confirm}" != "yes" ] && {
        echo "Uninstalling GAMS MIRO Server was interrupted."
        exit 0
    }
    stop
    $COMPOSE_BINARY -f docker-compose.yml down -v || exit 1
    rm -rf data models || {
        echo "Could not remove \"data\" and/or \"models\" directory. Check your permissions"
        exit 1
    }
    echo "GAMS MIRO Server uninstalled."
}

backup (){
    echo "Backing up GAMS MIRO Server"
    mkdir -p backup || {
        echo "Failed to create ./backup directory"
        exit 1
    }
    BACKUP_TIME=`date +%d-%m-%Y"_"%H_%M_%S`
    $COMPOSE_BINARY -f docker-compose.yml exec db pg_dumpall -c -U GMSMASTER | gzip > ./backup/dump_db_${BACKUP_TIME}.gz || {
        echo "Backup of the database failed"
        exit 1
    }
    tar --exclude "backup" --exclude "miro-server" -pczf ./backup/dump_miro_server_${BACKUP_TIME}.gz . || {
        echo "Backup of the root folder failed"
        exit 1
    }
    echo "Backup created successfully in: ${PWD}/backup with timestamp: ${BACKUP_TIME}"
}

restore (){
    BACKUP_TIME="${1}"
    [[ -z "${BACKUP_TIME}" ]] && {
        echo "Please specify the timestamp (format: %d-%m-%Y_%H_%M_%S) to be used for recovery as the first argument."
        exit 1
    }
    echo "Restoring GAMS MIRO Server from backup with timestamp: ${BACKUP_TIME} (backup directory: ${PWD}/backup)"
    tar -xpf ./backup/dump_miro_server_${BACKUP_TIME}.gz --exclude "backup" --exclude "miro-server" || {
        echo "Failed to restore root folder"
        exit 1
    }
    start
    sleep 5
    gunzip < ./backup/dump_db_${BACKUP_TIME}.gz | $COMPOSE_BINARY exec -T db psql -b -q -U GMSMASTER -d template1 > /dev/null || {
        echo "Failed to restore database"
        exit 1
    }
    echo -e "GAMS MIRO Server successfully restored.\n\n\
Errors stating that the default user GMSMASTER or the template database template1 cannot be dropped, \
as well as errors stating that users cannot be dropped because they do not exist, can be safely ignored."
}

case "$1" in
        stop)
            stop
            exit 0
            ;;

        uninstall)
            uninstall
            exit 0
            ;;

        restart)
            restart
            exit 0
            ;;

        start)
            start
            exit 0
            ;;

        install)
            install
            exit 0
          ;;

        build)
            build
            exit 0
          ;;

        pull)
            pull_images
            exit 0
            ;;

        update)
            update
            exit 0
            ;;

        backup)
            backup
            exit 0
            ;;

        restore)
            restore "$2"
            exit 0
            ;;

        *)
            echo $"Usage: $0 install|build|start|stop|restart|pull|update|backup|restore|uninstall"
            exit 1
esac
