#!/usr/bin/env bash
VERSION="0.1"
VERBOSE=false
SSLOPTION=false
AWSREGION="us-west-2"
US_W_1="ami-6d1ffd0e"
US_W_2="ami-7be8a103"
US_E_1="ami-b3be85cc"
US_E_2="ami-cc7a40a9"
AMI_IMAGE=$US_W_2
AWS_CLI=$(which aws)
DOCKER_CLI=$(which docker)
DOCKER_IMG="hunterlong/statup"
AWS_ECS="$AWS_CLI --output json"
DOCKER_PORT=8080

function usage() {
cat <<EOM
##### Statup Installer #####
A simple shell script that will help you install Statup on your local machine, AWS, or Docker.

Commands:
    install             Install statup to your local system
    aws                 Create a new EC2 instance running Statup
    docker              Start the latest Statup Docker image
    docker-compose      Create Statup with a Postgres database
    version             Return the latest version of Statup

Available Flags:
    -k | --aws-access-key        AWS Access Key ID. May also be set as environment variable AWS_ACCESS_KEY_ID
    -s | --aws-secret-key        AWS Secret Access Key. May also be set as environment variable AWS_SECRET_ACCESS_KEY
    -r | --region                AWS Region Name. May also be set as environment variable AWS_DEFAULT_REGION
    -x | --verbose               Verbose output

Visit the github repo at: https://github.com/hunterlong/statup
EOM
    exit 3
}

# Check requirements
function require() {
    getOS
    command -v "$1" > /dev/null 2>&1 || {
        echo "Some of the required software is not installed:"
        APP="$1" >&2;
        echo "    Required application: $APP"
        if [ $OS == "osx" ]; then
            echo "    You can run 'brew install $APP'"
        elif [ $OS == "linux" ]; then
            echo "    You can run 'apt install $APP'"
        fi
        exit 4;
    }
}

# Get the latest release from github
get_latest_release() {
  STATUP_VERSION=$(curl --silent "https://api.github.com/repos/$DOCKER_IMG/releases/latest" | jq -r .tag_name)
}

# auto set AWS environment variables
function setAWSPresets {
    if [ -z ${AWS_DEFAULT_REGION+x} ];
      then unset AWS_DEFAULT_REGION
      else
              AWS_ECS="$AWS_ECS --region $AWS_DEFAULT_REGION"
    fi
    if [ -z ${AWS_PROFILE+x} ];
      then unset AWS_PROFILE
      else
              AWS_ECS="$AWS_ECS --profile $AWS_PROFILE"
    fi
}

# ask the user to inser their AWS region
function awsAskRegion {
    if [ -z ${AWS_DEFAULT_REGION+x} ]; then
      read -p "Enter the AWS Region: "  AWSREGION
    else
      AWSREGION=$AWS_DEFAULT_REGION
    fi
}

# ask for the EC2 instance name
function askEC2Name {
    read -p "Enter the Name for EC2 Instance: "  SERVERNAME
}

# ask user if they want to use SSL
function askSSLOption {
    read -p "Do you want to install a SSL certificate? (y/N):"  SSLOPTION
}

# ask user for domain for SSL
function askSSLDomain {
    read -p "Enter the Domain to attach the SSL certificate on: "  SSLDOMAIN
}

# ask user for email for Letencrypt
function askSSLEmail {
    read -p "Enter the Email for Lets Encrypt: "  SSLEMAIL
}

# ask user for their EC2 Keypair for instance
function askEC2KeyName {
    read -p "Enter the Keypair for EC2 Instance: "  EC2KEYNAME
}

# ask user to create a new AWS security group namne
function askSecurityName {
    read -p "Enter a name for the new Security Group: "  EC2SECGROUP
}

# ask user if they want to install statup to the bin folder
function askInstallGlobal {
    read -p "Do you want to move Statup to the bin folder? (y/N): "  MOVEBIN
}

# ask user if they want statup to start on boot
function askInstallSystemCTL {
    read -p "Do you want to auto start Statup on boot? (y/N): "  SYSTEMCTL
}

# Task to create a new AWS security group
function awsSecurityGroup {
  echo "Running task: Creating Security Group";
  GROUPID=`$AWS_ECS ec2 create-security-group --group-name "$EC2SECGROUP" --description "Statup HTTP Server on port 80 and 443" | jq -r .GroupId`
  echo "Created new security group: $GROUPID";
  awsAuthSecurityGroup
}

# Task to open ports 80 and 443 for the security group
function awsAuthSecurityGroup {
  $AWS_ECS ec2 authorize-security-group-ingress --group-id $GROUPID --protocol tcp --port 80 --cidr 0.0.0.0/0
  $AWS_ECS ec2 authorize-security-group-ingress --group-id $GROUPID --protocol tcp --port 443 --cidr 0.0.0.0/0
  echo "Authorize security group to be open on ports 80 and 443";
}

function awsCreateEC2 {
  NEW_SRV=`$AWS_ECS ec2 run-instances --image-id $US_W_2 --count 1 --instance-type t2.nano --key-name $EC2KEYNAME --security-group-ids $GROUPID`
  INSTANCE_ID=$(echo "${NEW_SRV}" | jq -r .Instances[0].InstanceId)
  EC2_STATUS=$(echo "${NEW_SRV}" | jq -r .Instances[0].StateReason.Message)
  echo "New EC2 instance created: $INSTANCE_ID with status $EC2_STATUS";
}

# task to created a new EC2 instance with statup image
function ec2TaskComplete {
  echo "New EC2 instance is ready! $INSTANCE_ID with status $EC2_STATUS";
  echo "Instance ID: $INSTANCE_ID with status $EC2_STATUS";
  echo "Public DNS: $EC2_DNS";
  if [ $SSLOPTION == "y" ]; then
    echo "Now you have to add a CNAME DNS record on $SSLDOMAIN pointing to $EC2_DNS"
  fi
}

# function to check the EC2 instance
function checkEC2Instance {
  SRV_INFO=`$AWS_ECS ec2 describe-instances --instance-ids $INSTANCE_ID`
  EC2_STATUS=$(echo "${SRV_INFO}" | jq -r .Reservations[0].Instances[0].State.Name)
  EC2_DNS=$(echo "${SRV_INFO}" | jq -r .Reservations[0].Instances[0].PublicDnsName)
  EC2_STATUS=$(echo "${SRV_INFO}" | jq -r .Reservations[0].Instances[0].State.Name)
  if [ $EC2_STATUS == '"pending"' ]; then
    echo "EC2 instance is still being created: $INSTANCE_ID";
    sleep 2
    checkEC2Instance
  fi
}

# function to create the Statup EC2 instance
function awsTask {
    setAWSPresets
    askEC2Name
    awsAskRegion
    askSecurityName
    askEC2KeyName
    askSSLOption
    if [ $SSLOPTION == "y" ]; then
        askSSLDomain
        askSSLEmail
    fi
    awsSecurityGroup
    awsCreateEC2
    checkEC2Instance
    ec2TaskComplete
}

# function to move the statup binary to the bin folder
function moveToBin {
    mv statup /usr/local/bin/statup
}

# function to install a systemctl service to the local system
function installSystemCTL {
FILE=statup.service
cat > $FILE <<- EOM
[Unit]
Description=Statup Server
After=network.target
After=systemd-user-sessions.service
After=network-online.target

[Service]
Type=simple
Restart=always
ExecStart=/usr/local/bin/statup

[Install]
WantedBy=multi-user.target
EOM
echo "Installing systemctl service file to: /etc/systemd/system/$FILE"
mv $FILE /etc/systemd/system/$FILE
systemctl daemon-reload
systemctl enable statup.service
systemctl start statup
echo "Statup has been installed to SystemCTL and will start on boot"
}


function downloadBin {
     getOS
     getArch
     get_latest_release
     GIT_DOWNLOAD="https://github.com/$DOCKER_IMG/releases/download/$STATUP_VERSION/statup-$OS-$ARCH.tar.gz"
     echo "Downloading Statup $STATUP_VERSION from $GIT_DOWNLOAD"
     curl -L --silent $GIT_DOWNLOAD | tar xz
     echo "Download complete"
}

# install statup locally from github
function localTask {
     downloadBin
     echo "Try Statup by running 'statup version'!"
     askInstallGlobal
     if [ $MOVEBIN == "y" ]; then
        moveToBin
        echo "Statup can now be ran anywhere with command 'statup'"
        echo "Install location: /usr/local/bin/statup"
        if [ $OS == "linux" ]; then
          askInstallSystemCTL
          if [ $SYSTEMCTL == "y" ]; then
            installSystemCTL
          fi
        fi
    fi
}

function uninstallTask {
    rm -f /usr/local/bin/statup
}

# start the Statup docker image
function dockerTask {
     echo "Starting Statup Docker container on port $DOCKER_PORT"
     $DOCKER_CLI run -d -p $DOCKER_PORT:8080 $DOCKER_IMG
}

# get 64x or 32 machine arch
function getArch {
    MACHINE_TYPE=`uname -m`
    if [ ${MACHINE_TYPE} == 'x86_64' ]; then
      ARCH="x64"
    else
      ARCH="x32"
    fi
}

# get the users operating system
function getOS {
    OS="`uname`"
    case $OS in
      'Linux')
        OS='linux'
        alias ls='ls --color=auto'
        ;;
      'FreeBSD')
        OS='freebsd'
        alias ls='ls -G'
        ;;
      'WindowsNT')
        OS='windows'
        ;;
      'Darwin')
        OS='osx'
        ;;
      'SunOS')
        OS='solaris'
        ;;
      'AIX') ;;
      *) ;;
    esac
}

function echoVersion {
    require jq
    get_latest_release
    echo "Statup Latest: $STATUP_VERSION"
    echo "Statuper Tool: v$VERSION"
}

# main CLI entrypoint
if [ "$BASH_SOURCE" == "$0" ]; then
    set -o errexit
    set -o pipefail
    set -u
    set -e
    # If no args are provided, display usage information
    if [ $# == 0 ]; then usage; fi

    COMMD=$1

    # Loop through arguments, two at a time for key and value
    while [[ $# -gt 0 ]]
    do
        key="$1"
        case $key in
            -k|--aws-access-key)
                AWS_ACCESS_KEY_ID="$2"
                shift # past argument
                ;;
            -s|--aws-secret-key)
                AWS_SECRET_ACCESS_KEY="$2"
                shift # past argument
                ;;
            -r|--region)
                AWS_DEFAULT_REGION="$2"
                shift # past argument
                ;;
            -p|--port)
                DOCKER_PORT="$2"
                shift # past argument
                ;;
            -x|--verbose)
                VERBOSE=true
                ;;
            *)
            ;;
        esac
        shift # past argument or value
    done

    if [ $VERBOSE == true ]; then
        set -x
    fi

    case $COMMD in
            aws)
                require aws
                require jq
                awsTask
                exit 0
                ;;
            docker)
                require docker
                dockerTask
                exit 0
                ;;
            docker-compose)
                require docker-compose
                dockerComposeTask
                exit 0
                ;;
            install)
                require jq
                require curl
                require tar
                localTask
                shift # past argument
                ;;
            uninstall)
                uninstallTask
                shift # past argument
                ;;
            version|v)
                echoVersion
                exit 0
                ;;
                *)
            ;;
        esac
        shift # past argument or value
    fi
    exit 0

fi