#!/bin/bash

set -eu -o pipefail

# change this to a hash when we make a upgrade release
readonly LOG_FILE="/var/log/cloudron-setup.log"
readonly MINIMUM_DISK_SIZE_GB="18" # this is the size of "/" and required to fit in docker images 18 is a safe bet for different reporting on 20GB min
readonly MINIMUM_MEMORY="974"      # this is mostly reported for 1GB main memory (DO 992, EC2 990, Linode 989, Serverdiscounter.com 974)

readonly curl="curl --fail --connect-timeout 20 --retry 10 --retry-delay 2 --max-time 2400"

# copied from cloudron-resize-fs.sh
readonly rootfs_type=$(LC_ALL=C df --output=fstype / | tail -n1)
readonly physical_memory=$(LC_ALL=C free -m | awk '/Mem:/ { print $2 }')
readonly disk_size_bytes=$(LC_ALL=C df --output=size / | tail -n1)
readonly disk_size_gb=$((${disk_size_bytes}/1024/1024))

readonly RED='\033[31m'
readonly GREEN='\033[32m'
readonly DONE='\033[m'

# verify the system has minimum requirements met
if [[ "${rootfs_type}" != "ext4" ]]; then
    echo "Error: Cloudron requires '/' to be ext4" # see #364
    exit 1
fi

if [[ "${physical_memory}" -lt "${MINIMUM_MEMORY}" ]]; then
    echo "Error: Cloudron requires atleast 1GB physical memory"
    exit 1
fi

if [[ "${disk_size_gb}" -lt "${MINIMUM_DISK_SIZE_GB}" ]]; then
    echo "Error: Cloudron requires atleast 20GB disk space (Disk space on / is ${disk_size_gb}GB)"
    exit 1
fi

if systemctl -q is-active box; then
    echo "Error: Cloudron is already installed. To reinstall, start afresh"
    exit 1
fi

initBaseImage="true"
provider="generic"
requestedVersion=""
apiServerOrigin="https://api.cloudron.io"
webServerOrigin="https://cloudron.io"
sourceTarballUrl=""
rebootServer="true"

args=$(getopt -o "" -l "help,skip-baseimage-init,provider:,version:,env:,skip-reboot" -n "$0" -- "$@")
eval set -- "${args}"

while true; do
    case "$1" in
    --help) echo "See https://docs.cloudron.io/installation/ on how to install Cloudron"; exit 0;;
    --provider) provider="$2"; shift 2;;
    --version) requestedVersion="$2"; shift 2;;
    --env)
        if [[ "$2" == "dev" ]]; then
            apiServerOrigin="https://api.dev.cloudron.io"
            webServerOrigin="https://dev.cloudron.io"
        elif [[ "$2" == "staging" ]]; then
            apiServerOrigin="https://api.staging.cloudron.io"
            webServerOrigin="https://staging.cloudron.io"
        fi
        shift 2;;
    --skip-baseimage-init) initBaseImage="false"; shift;;
    --skip-reboot) rebootServer="false"; shift;;
    --) break;;
    *) echo "Unknown option $1"; exit 1;;
    esac
done

# Only --help works as non-root
if [[ ${EUID} -ne 0 ]]; then
    echo "This script should be run as root." > /dev/stderr
    exit 1
fi

# Only --help works with mismatched ubuntu
ubuntu_version=$(lsb_release -rs)
if [[ "${ubuntu_version}" != "16.04" && "${ubuntu_version}" != "18.04" && "${ubuntu_version}" != "20.04" ]]; then
    echo "Cloudron requires Ubuntu 16.04, 18.04 or 20.04" > /dev/stderr
    exit 1
fi

# Can only write after we have confirmed script has root access
echo "Running cloudron-setup with args : $@" > "${LOG_FILE}"

echo ""
echo "##############################################"
echo "         Cloudron Setup (${requestedVersion:-latest})"
echo "##############################################"
echo ""
echo " Follow setup logs in a second terminal with:"
echo " $ tail -f ${LOG_FILE}"
echo ""
echo " Join us at https://forum.cloudron.io for any questions."
echo ""

if [[ "${initBaseImage}" == "true" ]]; then
    echo "=> Installing software-properties-common"
    if ! apt-get install -y software-properties-common &>> "${LOG_FILE}"; then
        echo "Could not install software-properties-common (for add-apt-repository below). See ${LOG_FILE}"
        exit 1
    fi

    echo "=> Updating apt and installing script dependencies"
    if ! apt-get update &>> "${LOG_FILE}"; then
        echo "Could not update package repositories. See ${LOG_FILE}"
        exit 1
    fi

    if ! DEBIAN_FRONTEND=noninteractive apt-get -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" -y install curl python3 ubuntu-standard -y &>> "${LOG_FILE}"; then
        echo "Could not install setup dependencies (curl). See ${LOG_FILE}"
        exit 1
    fi
fi

echo "=> Checking version"
if ! releaseJson=$($curl -s "${apiServerOrigin}/api/v1/releases?boxVersion=${requestedVersion}"); then
    echo "Failed to get release information"
    exit 1
fi

if [[ "$requestedVersion" == "" ]]; then
    version=$(echo "${releaseJson}" | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(obj["version"])')
else
    version="${requestedVersion}"
fi

if ! sourceTarballUrl=$(echo "${releaseJson}" | python3 -c 'import json,sys;obj=json.load(sys.stdin);print(obj["info"]["sourceTarballUrl"])'); then
    echo "No source code for version '${requestedVersion:-latest}'"
    exit 1
fi

echo "=> Downloading version ${version} ..."
box_src_tmp_dir=$(mktemp -dt box-src-XXXXXX)

if ! $curl -sL "${sourceTarballUrl}" | tar -zxf - -C "${box_src_tmp_dir}"; then
    echo "Could not download source tarball. See ${LOG_FILE} for details"
    exit 1
fi

if [[ "${initBaseImage}" == "true" ]]; then
    echo -n "=> Installing base dependencies and downloading docker images (this takes some time) ..."
    # initializeBaseUbuntuImage.sh args (provider, infraversion path) are only to support installation of pre 5.3 Cloudrons
    if ! /bin/bash "${box_src_tmp_dir}/baseimage/initializeBaseUbuntuImage.sh" "generic" "../src" &>> "${LOG_FILE}"; then
        echo "Init script failed. See ${LOG_FILE} for details"
        exit 1
    fi
    echo ""
fi

# The provider flag is still used for marketplace images
echo "=> Installing version ${version} (this takes some time) ..."
mkdir -p /etc/cloudron
echo "${provider}" > /etc/cloudron/PROVIDER

if ! /bin/bash "${box_src_tmp_dir}/scripts/installer.sh" &>> "${LOG_FILE}"; then
    echo "Failed to install cloudron. See ${LOG_FILE} for details"
    exit 1
fi

mysql -uroot -ppassword -e "REPLACE INTO box.settings (name, value) VALUES ('api_server_origin', '${apiServerOrigin}');" 2>/dev/null
mysql -uroot -ppassword -e "REPLACE INTO box.settings (name, value) VALUES ('web_server_origin', '${webServerOrigin}');" 2>/dev/null

echo -n "=> Waiting for cloudron to be ready (this takes some time) ..."
while true; do
    echo -n "."
    if status=$($curl -s -f "http://localhost:3000/api/v1/cloudron/status" 2>/dev/null); then
        break # we are up and running
    fi
    sleep 10
done

if ! ip=$(curl -s --fail --connect-timeout 2 --max-time 2 https://api.cloudron.io/api/v1/helper/public_ip | sed -n -e 's/.*"ip": "\(.*\)"/\1/p'); then
    ip='<IP>'
fi
echo -e "\n\n${GREEN}After reboot, visit https://${ip} and accept the self-signed certificate to finish setup.${DONE}\n"

if [[ "${rebootServer}" == "true" ]]; then
    systemctl stop box mysql # sometimes mysql ends up having corrupt privilege tables

    read -p "The server has to be rebooted to apply all the settings. Reboot now ? [Y/n] " yn
    yn=${yn:-y}
    case $yn in
        [Yy]* ) systemctl reboot;;
        * ) exit;;
    esac
fi
