#!/usr/bin/env bash

VERSION="4.0.2" # bumped to support vessel --help, vessel --version

# define colors that are used in the help screen

ESC_SEQ="\x1b["
COL_RESET=${ESC_SEQ}"39;49;00m"
COL_LYELLOW=${ESC_SEQ}"33;01m"
COL_LGREEN=${ESC_SEQ}"32;01m"
COL_CYAN=${ESC_SEQ}"0;36m"
COL_GREEN=${ESC_SEQ}"0;32m"
COL_MAGENTA=${ESC_SEQ}"0;35m"

CONTAINER_APP="app"
CONTAINER_MYSQL="mysql"
CONTAINER_NODE="node"

UNAMEOUT="$(uname -s)"
case "${UNAMEOUT}" in
    Linux*)             MACHINE=linux;;
    Darwin*)            MACHINE=mac;;
    MINGW64_NT-10.0*)   MACHINE=mingw64;;
    *)                  MACHINE="UNKNOWN"
esac

if [ "$MACHINE" == "UNKNOWN" ]; then
    echo "Unsupported system type"
    echo "System must be a Macintosh, Linux or Windows"
    echo ""
    echo "System detection determined via uname command"
    echo "If the following is empty, could not find uname command: $(which uname)"
    echo "Your reported uname is: $(uname -s)"
fi

# Set environment variables for dev
if [ "$MACHINE" == "linux" ]; then
    if grep -q Microsoft /proc/version; then # WSL
        export XDEBUG_HOST=10.0.75.1
    else
        if [ "$(command -v ip)" ]; then
            export XDEBUG_HOST=$(ip addr show docker0 | grep "inet\b" | awk '{print $2}' | cut -d/ -f1)
        else
            export XDEBUG_HOST=$(ifconfig docker0 | grep "inet addr" | cut -d ':' -f 2 | cut -d ' ' -f 1)
        fi
    fi
    SEDCMD="sed -i"
elif [ "$MACHINE" == "mac" ]; then
    export XDEBUG_HOST=$(ipconfig getifaddr en0) # Ethernet

    if [ -z "$XDEBUG_HOST" ]; then
        export XDEBUG_HOST=$(ipconfig getifaddr en1) # Wifi
    fi
    SEDCMD="sed -i .bak"
elif [ "$MACHINE" == "mingw64" ]; then # Git Bash
    export XDEBUG_HOST=10.0.75.1
    SEDCMD="sed -i"
fi

export APP_PORT=${APP_PORT:-80}
export MYSQL_PORT=${MYSQL_PORT:-3306}
export WWWUSER=${WWWUSER:-$UID}

showVersion() {
    intro="\n🐳 ${COL_GREEN}Vessel for Docker${COL_RESET}\n"
    intro="$intro   ${COL_CYAN}Version ${VERSION}\n${COL_RESET}"

    printf "$intro"
}

showHelp() {

    showVersion

    usage="${COL_LYELLOW}Usage:\n${COL_RESET}"
    usage="$usage  ./vessel <cmd> <options>"

    commands="${COL_LYELLOW}Commands:\n${COL_RESET}"
    commands="$commands  art | artisan <cmd>         Run Laravel Artisan CLI in ${COL_MAGENTA}${CONTAINER_APP}${COL_RESET} container\n"
    commands="$commands  composer <cmds>             Run Composer in ${COL_MAGENTA}${CONTAINER_APP}${COL_RESET} container\n"
    commands="$commands  mysql                       Run MySQL CLI in ${COL_MAGENTA}${CONTAINER_MYSQL}${COL_RESET} container\n"
    commands="$commands  dump (autoload)             Performs composer dump-autoload in ${COL_MAGENTA}${CONTAINER_APP}${COL_RESET} container\n"
    commands="$commands  exec <container>            Execute a command in a running container\n"
    commands="$commands  help                        Shows Help screen\n"
    commands="$commands  logs <container> < -f >     Displays all logs for <container> and optionally tail\n"
    commands="$commands  npm                         Execute npm command using ${COL_MAGENTA}${CONTAINER_NODE}${COL_RESET} container\n"
    commands="$commands  ps                          Display list of all running containers in current directory\n"
    commands="$commands  start < -l >                Starts all containers defined in ${COL_LGREEN}docker-compose.yml${COL_RESET} file\n"
    commands="$commands  stop                        Stops all containers defined in ${COL_LGREEN}docker-compose.yml${COL_RESET} file\n"
    commands="$commands  test [params]               Runs PHPUnit using supplied options in ${COL_MAGENTA}${CONTAINER_APP}${COL_RESET} container\n"
    commands="$commands  tinker                      Runs Tinker in ${COL_MAGENTA}${CONTAINER_APP}${COL_RESET} container\n"
    commands="$commands  npm <options>               Runs npm using supplied options in ${COL_MAGENTA}${CONTAINER_NODE}${COL_RESET} container\n"
    commands="$commands  yarn <options>              Runs yarn using supplied options in ${COL_MAGENTA}${CONTAINER_NODE}${COL_RESET} container\n"
#    commands="$commands  gulp <task>                 Runs gulp task in ${COL_MAGENTA}${CONTAINER_NODE}${COL_RESET} container\n"

    options="${COL_LYELLOW}Options:\n${COL_RESET}"
    options="$options --help, -h                   Shows Help (this screen)\n"
#    options="$options --logs, -l                   Run containers in detached mode (with logging)\n"
    options="$options --version, -V, version       Show Version\n"

    examples="${COL_LYELLOW}Examples:\n${COL_RESET}"
    examples="$examples  ${COL_CYAN}$ ./vessel start${COL_RESET}\n"
    examples="$examples  ${COL_CYAN}$ ./vessel stop${COL_RESET}\n"
    examples="$examples  ${COL_CYAN}$ ./vessel dump${COL_RESET}\n"
    examples="$examples  ${COL_CYAN}$ ./vessel logs # all container logs${COL_RESET}\n"
    examples="$examples  ${COL_CYAN}$ ./vessel composer require <vendor/package>${COL_RESET}\n"
    examples="$examples  ${COL_CYAN}$ ./vessel mysql${COL_RESET}\n"
    examples="$examples  ${COL_CYAN}$ ./vessel artisan migrate --seed${COL_RESET}\n"
    examples="$examples  ${COL_CYAN}$ ./vessel art db:seed${COL_RESET}\n"
    examples="$examples  ${COL_CYAN}$ ./vessel test --filter=MyFilter${COL_RESET}\n"

    printf "\n"
    printf "$usage\n\n"
    printf "$commands\n"
    printf "$options\n"
    printf "$examples\n"

}

# Is the environment running
PSRESULT="$(docker-compose ps -q)"
if [ ! -z "$PSRESULT" ]; then
    EXEC="yes"
else
    EXEC="no"
fi

# Create base docker-compose command to run
COMPOSE="docker-compose"

# If we pass any arguments...
if [ $# -gt 0 ]; then

    # Source .env, which can over-ride env vars
    # such as APP_PORT, MYSQL_PORT, and WWWUSER
    if [ -f .env ]; then
        source .env
    fi


    if [ "$1" == "--version" ] || [ "$1" == "-v" ] || [ "$1" == "version" ]; then
        showVersion
        exit 1
    fi
    if [ "$1" == "--help" ] || [ "$1" == "-H" ] || [ "$1" == "help" ]; then
        showHelp
        exit 1
    fi


    # Edit .env file to set correct hostnames for mysql/redis
    if [ "$1" == "init" ]; then
        echo "VESSEL: Initializing Vessel..."
        COMPOSER=$(which composer)

        echo "VESSEL: Installing Predis"
        if [ -z "$COMPOSER" ]; then
          docker run -u $UID --rm -it \
            -v $(pwd):/opt \
            -w /opt \
            shippingdocker/php-composer:latest \
            composer require predis/predis
        else
            $COMPOSER require predis/predis
        fi

        if [ ! -f .env ]; then
            echo "No .env file found within current working directory $(pwd)"
            echo "Create a .env file before re-initializing"
            exit 0
        fi

        echo "VESSEL: Setting .env Variables"
        cp .env .env.bak.vessel

        if [ ! -z "$(grep "DB_HOST" .env)" ]; then
            $SEDCMD "s/DB_HOST=.*/DB_HOST=mysql/" .env
        else
            echo "DB_HOST=mysql" >> .env
        fi

        if [ ! -z "$(grep "CACHE_DRIVER" .env)" ]; then
            $SEDCMD "s/CACHE_DRIVER=.*/CACHE_DRIVER=redis/" .env
        else
            echo "CACHE_DRIVER=redis" >> .env
        fi

        if [ ! -z "$(grep "SESSION_DRIVER" .env)" ]; then
            $SEDCMD "s/SESSION_DRIVER=.*/SESSION_DRIVER=redis/" .env
        else
            echo "SESSION_DRIVER=redis" >> .env
        fi

        if [ ! -z "$(grep "REDIS_HOST" .env)" ]; then
            $SEDCMD "s/REDIS_HOST=.*/REDIS_HOST=redis/" .env
        else
            echo "REDIS_HOST=redis" >> .env
        fi

        if [ -f .env.bak ]; then
            rm .env.bak
        fi

        if [ ! -f vessel ]; then
            echo "No vessel file found within current working directory $(pwd)"
            echo "Have you run the artisan vendor:publish command yet?"
            exit 0
        fi

        echo "VESSEL: Making vessel command available"
        chmod +x vessel

        echo ""
        echo "VESSEL: Complete!"
        echo "VESSEL: You can now use Vessel"
        echo "VESSEL: Try starting it:"
        echo "./vessel start"


    # Start up containers
    elif [ "$1" == "start" ]; then
        $COMPOSE up -d

    # Stop the containers
    elif [ "$1" == "stop" ]; then
        $COMPOSE down

    # If "php" is used, pass-thru to "php"
    # inside a new container
    elif [ "$1" == "php" ]; then
        shift 1
        if [ "$EXEC" == "yes" ]; then
            $COMPOSE exec \
                -u vessel \
                app \
                php "$@"
        else
            $COMPOSE run --rm \
                app \
                php "$@"
        fi

    # If "art" is used, pass-thru to "artisan"
    # inside a new container
    elif [ "$1" == "artisan" ] || [ "$1" == "art" ]; then
        shift 1
        if [ "$EXEC" == "yes" ]; then
            $COMPOSE exec \
                -u vessel \
                app \
                php artisan "$@"
        else
            $COMPOSE run --rm \
                app \
                php artisan "$@"
        fi

    # If "composer" is used, pass-thru to "composer"
    # inside a new container
    elif [ "$1" == "composer" ] || [ "$1" == "comp" ]; then
        shift 1
        if [ "$EXEC" == "yes" ]; then
            $COMPOSE exec \
                -u vessel \
                app \
                composer "$@"
        else
            $COMPOSE run --rm \
                app \
                composer "$@"
        fi

    # If "test" is used, run unit tests,
    # pass-thru any extra arguments to php-unit
    elif [ "$1" == "test" ]; then
        shift 1
        if [ "$EXEC" == "yes" ]; then
            $COMPOSE exec \
                -u vessel \
                app \
                ./vendor/bin/phpunit "$@"
        else
            $COMPOSE run --rm \
                app \
                ./vendor/bin/phpunit "$@"
        fi

    # If "tinker" is used, drop into the REPL
    # inside a new container
    elif [ "$1" == "tinker" ] ; then
        shift 1
        if [ "$EXEC" == "yes" ]; then
            $COMPOSE exec \
                -u vessel \
                app \
                php artisan tinker
        else
            $COMPOSE run --rm \
                app \
                php artisan tinker
        fi

    # If "node" is used, run node
    # from our node container
    elif [ "$1" == "node" ]; then
        shift 1
        $COMPOSE run --rm \
            node \
            node "$@"

    # If "npm" is used, run npm
    # from our node container
    elif [ "$1" == "npm" ]; then
        shift 1
        $COMPOSE run --rm \
            node \
            npm "$@"

    # If "yarn" is used, run yarn
    # from our node container
    elif [ "$1" == "yarn" ]; then
        shift 1
        $COMPOSE run --rm \
            node \
            yarn "$@"

    # If "gulp" is used, run gulp
    # from our node container
    elif [ "$1" == "gulp" ]; then
        shift 1
        $COMPOSE run --rm \
            node \
            ./node_modules/.bin/gulp "$@"

    # If "dump" is used, run mysqldump
    # from our mysql container
    elif [ "$1" == "dump" ]; then
        shift 1
        if [ "$EXEC" == "yes" ]; then
            $COMPOSE exec \
                mysql \
                bash -c 'MYSQL_PWD=$MYSQL_ROOT_PASSWORD mysqldump -u root --default-character-set=utf8mb4 $MYSQL_DATABASE'
        else
            $COMPOSE run --rm \
                mysql \
                bash -c 'MYSQL_PWD=$MYSQL_ROOT_PASSWORD mysqldump -u root --default-character-set=utf8mb4 $MYSQL_DATABASE'
        fi

    # If "mysql" is used, run mysql
    # from our mysql container
    elif [ "$1" == "mysql" ]; then
        shift 1
        if [ "$EXEC" == "yes" ]; then
            $COMPOSE exec \
                mysql \
                bash -c 'MYSQL_PWD=$MYSQL_ROOT_PASSWORD mysql -u root $MYSQL_DATABASE'
        else
            echo "Error: This command can only be run while a MySQL container is running mysqld (mysql server)."
            echo "This command cannot run the server and the mysql client at the same time."
        fi

    # If "ssh" is used, pass-thru to "ssh"
    # inside a new container
    # e.g.: ./vessel ssh app
    # e.g.: ./vessel ssh mysql
    elif [ "$1" == "ssh" ]; then
        shift 1
        if [ "$EXEC" == "yes" ] && [ "$1" != "node" ]; then
            $COMPOSE exec \
                -u vessel \
                $1 \
                bash
        else
            $COMPOSE run --rm \
                $1 \
                bash
        fi

    # Else, pass-thru args to docker-compose
    else
        $COMPOSE "$@"
    fi
else
    # Use the docker-compose ps command if nothing else passed through
    $COMPOSE ps
fi


