#!/bin/bash

echo "
  ____             __          _       _                
 / ___|    __ _   / _|   ___  | |     (_)  _ __     ___ 
 \___ \   / _\` | | |_   / _ \ | |     | | | '_ \   / _ \\
  ___) | | (_| | |  _| |  __/ | |___  | | | | | | |  __/
 |____/   \__,_| |_|    \___| |_____| |_| |_| |_|  \___|
"

export STREAM=${STREAM:-0}

RELEASE="${RELEASE}"
if [ -n "$RELEASE" ]; then
    RELEASE="-$RELEASE"
fi

qrcode() {
    echo "https://discord.gg/BDUa5UQnTW"
    echo
    echo "Visit the above address to join the SafeLine discord group"
}

confirm() {
    echo -e -n "\033[34m[SafeLine] $* \033[1;36m(Y/n)\033[0m"
    read -n 1 -s opt

    [[ "$opt" == $'\n' ]] || echo

    case "$opt" in
        'y' | 'Y' ) return 0;;
        'n' | 'N' ) return 1;;
        *) confirm "$1";;
    esac
}

info() {
    echo -e "\033[37m[SafeLine] $*\033[0m"
}

warning() {
    echo -e "\033[33m[SafeLine] $*\033[0m"
}

abort() {
    qrcode
    echo -e "\033[31m[SafeLine] $*\033[0m"
    exit 1
}

command_exists() {
	command -v "$1" 2>&1
}

check_ssse3() {
    [[ "$ARCH" =~ "aarch" || "$ARCH" =~ "arm" ]] && return 0
    lscpu | grep -q ssse3 || cat /proc/cpuinfo | grep -q ssse3 || \
    abort "SafeLine needs to run on a CPU that supports the ssse3 instruction set. Please configure the virtual machine to enable CPU ssse3 instruction set."
}

check_ssse3

check_container_health() {
    local container_name=$1
    local max_retry=30
    local retry=0
    local health_status="unhealthy"
    info "Waiting for $container_name to be healthy"
    while [[ "$health_status" == "unhealthy" && $retry -lt $max_retry ]]; do
        health_status=$(docker inspect --format='{{.State.Health.Status}}' $container_name 2>/dev/null || info 'unhealthy')
        sleep 5
        retry=$((retry+1))
    done
    if [[ "$health_status" == "unhealthy" ]]; then
        abort "Container $container_name is unhealthy"
    fi
    info "Container $container_name is healthy"
}

space_left() {
    dir="$1"
    while [ ! -d "$dir" ]; do
        dir=`dirname "$dir"`;
    done
    echo `df -h "$dir" --output='avail' | tail -n 1`
}

local_ips() {
    if [ -z `command_exists ip` ]; then
        ip_cmd="ip addr show"
    else
        ip_cmd="ifconfig -a"
    fi

    echo $($ip_cmd | grep -Eo 'inet (addr:)?([0-9]*\.){3}[0-9]*' | awk '{print $2}')
}

ips=`local_ips`
subnets="172.22.222 169.254.222 192.168.222"

for subnet in $subnets; do
    if [[ $ips != *$subnet* ]]; then
        SUBNET_PREFIX=$subnet
        break
    fi
done

start_docker() {
    systemctl start docker && systemctl enable docker
}

trap 'onexit' INT
onexit() {
    echo
    abort "User terminates the installation process"
}

safeline_path='/data/safeline'

if [ -z "$BASH" ]; then
    abort "Please use bash to execute the current script, please refer to the latest technical documentation https://waf.chaitin.com/"
fi

if [ ! -t 0 ]; then
    abort "STDIN is not a standard input device, please refer to the latest technical documentation https://waf.chaitin.com/"
fi

if [ "$#" -ne "0" ]; then
    abort "The current script does not require any parameters, please refer to the latest technical documentation https://waf.chaitin.com/"
fi

if [ "$EUID" -ne "0" ]; then
    abort "Please run with root privileges"
fi
info "The script calling method is confirmed to be normal"

if [ -z `command_exists docker` ]; then
    warning "Docker is not installed"
    if confirm "Do you need to install Docker automatically?"; then
        curl -sSLk https://get.docker.com/ | bash
        if [ $? -ne "0" ]; then
            abort "Docker installation failed"
        fi
        info "Docker installation finished"
    else
        abort "Installation has been terminate"
    fi
fi
info "Docker is installed at: '`command -v docker`'"

start_docker
docker version > /dev/null 2>&1
if [ $? -ne "0" ]; then
    abort "Docker service is inactive"
fi
info "Docker service is active"

compose_command="docker compose"
if $compose_command version; then
    info "Docker Compose Plugin is found"
else
    warning "Docker Compose Plugin is not found"
    compose_command="docker-compose"
    if [ -z `command_exists "docker-compose"` ]; then
        warning "docker-compose is not found"
        if confirm "Do you need to install Docker Compose Plugin automatically"; then
            curl -sSLk https://get.docker.com/ | bash
            if [ $? -ne "0" ]; then
                abort "Docker Compose Plugin installation failed"
            fi
            info "Docker Compose Plugin installation finished"
            compose_command="docker compose"
        else
            abort "Installation has been terminate"
        fi
    else
        info "docker-compose is installed at: '`command -v docker-compose`'"
    fi
fi

while true; do
    echo -e -n "\033[34m[SafeLine] SafeLine directory (blank means '$safeline_path'): \033[0m"
    read input_path
    [[ -z "$input_path" ]] && input_path=$safeline_path

    if [[ ! $input_path == /* ]]; then
        warning "'$input_path' is not valid path"
        continue
    fi

    if [ -f "$input_path" ] || [ -d "$input_path" ]; then
        warning "'$input_path' path is exists"
        continue
    fi

    safeline_path=$input_path

    if confirm "Path '$safeline_path' has `space_left \"$safeline_path\"` of free space, SafeLine need 5GB to install, continue?"; then
        break
    fi
done

mkdir -p "$safeline_path"
if [ $? -ne "0" ]; then
    abort "Create SafeLine directory '$safeline_path' failed"
fi
info "Create SafeLine directory '$safeline_path' successful"
cd "$safeline_path"

curl "https://waf.chaitin.com/release/latest/compose.yaml" -sSLk -o compose.yaml
curl "https://waf.chaitin.com/release/latest/reset_tengine.sh" -sSLk -o reset_tengine.sh

if [ $? -ne "0" ]; then
    abort "Download compose.yaml failed"
fi
info "Download compose.yaml successful"

touch ".env"
if [ $? -ne "0" ]; then
    abort "Create .env failed"
fi
info "Create .env successful"

echo "SAFELINE_DIR=$safeline_path" >> .env

if [ $STREAM -eq 1 ]; then
    echo "IMAGE_TAG=latest-stream" >>".env"
else
    echo "IMAGE_TAG=latest" >>".env"
fi

echo "MGT_PORT=9443" >> .env
echo "POSTGRES_PASSWORD=$(LC_ALL=C tr -dc A-Za-z0-9 </dev/urandom | head -c 32)" >> .env
echo "SUBNET_PREFIX=$SUBNET_PREFIX" >> .env
ARCH=$(uname -m)
if [[ "$ARCH" =~ "aarch" || "$ARCH" =~ "arm" ]]; then
  echo "ARCH_SUFFIX=-arm" >>".env"
else
  echo "ARCH_SUFFIX=" >>".env"
fi

echo "IMAGE_PREFIX=chaitin" >>".env"
echo "RELEASE=$RELEASE" >>".env"
echo "REGION=-g" >>".env"

info "Downloading Docker image"

$compose_command up -d

if [ $? -ne "0" ]; then
    abort "Docker container starts failed"
fi

qrcode

check_container_health safeline-pg
check_container_health safeline-mgt
docker exec safeline-mgt /app/mgt-cli reset-admin --once

warning "SafeLine WAF has been installed, visit the following address to Web admin console"
warning "https://0.0.0.0:9443/"
for ip in $ips; do
    warning https://$ip:9443/
done

