#!/usr/bin/env bash

set -euo pipefail

acra_install_raise() {
    echo -e "\\nERROR: $*\\n" >&2
    exit 1
}

acra_install_detect_os() {
    os_type=$(uname | tr '[:upper:]' '[:lower:]')
    case "$os_type" in
        (linux)
            if [[ -f "/etc/os-release" ]]; then
                . /etc/os-release
                os="${ID,,}"
                os_ver="${VERSION_ID%%.*}"
                case "$os" in
                    (debian)
                        os_ver_name="${VERSION#*(}"
                        os_ver_name="${os_ver_name%)}"
                        ;;
                    (*)
                        os_ver_name="${VERSION_CODENAME:-${os_ver}}"
                        ;;
                esac
            else
                acra_install_raise "can not detect Linux version."
            fi
            ;;
        (*)
            acra_install_raise "OS family '$(uname)' is not supported."
            ;;
    esac
}

acra_install_help() {
echo "
Usage:
    acra_install.sh [option] ...

Options:
    common options:
        --repository <repository_name>
            Repository name, one of: 'ce', 'ee'.
            Default is 'ce'.
        --branch <branch_name>
            Repository  branch to install from.
            Default is 'stable'.
        --user <user>
        --password <password>
            User name and password for access to repository. Ignored for 'ce'.
        --yes
            Do not request confirmations.
        --skip-install-required
            Do not install required packages. Suppose they already
            present in system.
        --help
            Show this help message.

Examples:
    acra_install.sh
        Download and install pre-compiled package in your system.
    acra_install.sh --branch devel
        Download and install pre-compiled package from devel branch.
"
}

acra_install_parse_args() {
    flag_yes=""
    flag_skip_install_required=""
    while (( $# > 0 )); do
        arg="$1"
        shift
        case "$arg" in
            (--repository)
                [[ -n "${1:-}" ]] || acra_install_raise \
                    "repository name must be present next to --repository option."
                repository="$1"
                shift
                ;;
            (--branch)
                [[ -n "${1:-}" ]] || acra_install_raise \
                    "branch name must be present next to --branch option."
                branch="$1"
                shift
                ;;
            (--user)
                [[ -n "${1:-}" ]] || acra_install_raise \
                    "user name must be present next to --user option."
                user="$1"
                shift
                ;;
            (--password)
                [[ -n "${1:-}" ]] || acra_install_raise \
                    "password must be present next to --password option."
                password="$1"
                shift
                ;;
            (--yes)
                flag_yes=" -y"
                ;;
            (--skip-install-required)
                flag_skip_install_required="1"
                ;;
            (help|--help|-?|--?)
                acra_install_help
                exit 0
                ;;
            (*)
                acra_install_help
                exit 1
                ;;
        esac
    done
    repository="${repository:-ce}"
    branch="${branch:-stable}"
    if [[ -n "${password:-}" ]] && [[ -z "${user:-}" ]]; then
        acra_install_raise "user must be specified when password is provided"
    fi
    http_creds=''
    if [[ ! "$repository" == 'ce' ]]; then
        if [[ -n "${user:-}" ]]; then
            http_creds+="$user"
        fi
        if [[ -n "${password:-}" ]]; then
            http_creds+=":$password"
        fi
        if [[ -n "${http_creds}" ]]; then
            http_creds+='@'
        fi
    fi
}

acra_install_check() {
    OS_SUPPORTED=(
        debian:bookworm
        debian:bullseye
        debian:buster
        debian:stretch
        ubuntu:jammy
        ubuntu:focal
        ubuntu:bionic
        ubuntu:xenial
        centos:8
        centos:7
    )
    [[ " ${OS_SUPPORTED[@]} " =~ " $os:$os_ver_name " ]] ||
    acra_install_raise "OS version '$os $os_ver_name' is not supported."
}

acra_install_cmd() {
    echo -e "\\n== ${2:-Run command}"
    echo -e ">> $1\\n"
    eval "$1"
}

acra_install_cmd_sensitive() {
    echo -e "\\n== ${2:-Run command}"
    echo -e ">> *** sensitive data filtered ***\\n"
    eval "$1"
}

acra_install_cmd_sudo() {
    acra_install_cmd "${sudo_cmd}${1}" "${2}${sudo_msg}"
}

acra_install_required_packages() {
    case "$os" in
        (debian|ubuntu)
                acra_install_cmd_sudo \
                    "apt-get update" \
                    "Update APT"
                acra_install_cmd_sudo \
                    "apt-get${flag_yes} install apt-transport-https wget" \
                    "Install required packages"
            ;;
        (centos)
                if [[ "$os_ver" == '7' ]]; then
                    acra_install_cmd_sudo \
                        "yum${flag_yes} makecache fast" \
                        "Update YUM cache"
                fi
                acra_install_cmd_sudo \
                    "yum${flag_yes} install wget" \
                    "Install required packages"
            ;;
        (*)
            acra_install_raise "can not install package for this OS."
            ;;
    esac

}

acra_install_debian_add_repo() {
    local repo="$1"
    local creds="${2:-}"
    acra_install_cmd_sensitive \
        "echo \"deb https://${creds}pkgs-${repo}.cossacklabs.com/"\
"${branch}/${os} ${os_ver_name} main\" | (umask 0077; "\
"${sudo_cmd}tee /etc/apt/sources.list.d/cossacklabs-${repo}.list)" \
        "Add Cossack Labs ${repo} repository${sudo_msg}"
}

acra_install_centos_add_repo() {
    local repo="$1"
    local creds="${2:-}"
    acra_install_cmd_sensitive \
        "wget -qO - https://${creds}pkgs-${repo}.cossacklabs.com/"\
"${branch}/centos/cossacklabs.repo | (umask 0077; "\
"${sudo_cmd}tee /etc/yum.repos.d/cossacklabs-${repo}.repo)" \
        "Add Cossack Labs ${repo} repository${sudo_msg}"
    if [[ -n "$creds" ]]; then
        acra_install_cmd_sensitive \
            "sed -i \"s|baseurl=https://|baseurl=https://$creds|\" "\
"/etc/yum.repos.d/cossacklabs-${repo}.repo" \
            "Set credentials for Cossack Labs ${repo} repository"
    fi
}

acra_install_from_package() {
    if [[ -z $flag_skip_install_required ]]; then
        acra_install_required_packages
    fi

    local pkg='acra'
    if [[ ! "$repository" == 'ce' ]]; then
        pkg+="-${repository}"
    fi

    case "$os" in
        (debian|ubuntu)
            # Always download GPG key from CE repository (wo authentication)
            acra_install_cmd \
                "wget -qO - https://pkgs.cossacklabs.com/ce/gpg | "\
"${sudo_cmd}apt-key add -" \
                "Fetch Cossack Labs GPG key${sudo_msg}"
            # libthemis is in the CE repository, always required
            acra_install_debian_add_repo 'ce'
            if [[ ! "$repository" == 'ce' ]]; then
                acra_install_debian_add_repo "$repository" "$http_creds"
            fi
            acra_install_cmd_sudo \
                "apt-get update" \
                "Update APT"
            acra_install_cmd_sudo \
                "apt-get${flag_yes} install ${pkg}" \
                "Install ${pkg}"
            ;;
        (centos)
            # Always download GPG key from CE repository (wo authentication)
            acra_install_cmd_sudo \
                "rpm --import https://pkgs.cossacklabs.com/ce/gpg" \
                "Fetch Cossack Labs GPG key"
            # libthemis is in the CE repository, always required
            acra_install_centos_add_repo 'ce'
            if [[ ! "$repository" == 'ce' ]]; then
                acra_install_centos_add_repo "$repository" "$http_creds"
            fi
            if [[ "$os_ver" == '7' ]]; then
                acra_install_cmd_sudo \
                    "yum${flag_yes} makecache fast" \
                    "Update YUM cache"
            fi
            acra_install_cmd_sudo \
                "yum${flag_yes} install ${pkg}" \
                "Install ${pkg}"
            ;;
        (*)
            acra_install_raise "can not install package for this OS."
            ;;
    esac
}

acra_install_main() {
    if [[ $(whoami) == 'root' ]]; then
        sudo_cmd=""
        sudo_msg=""
    else
        sudo_cmd="sudo "
        sudo_msg=", sudo password might be required"
    fi
    acra_install_from_package
}

acra_install_post() {
    echo 'All done.'
}

acra_install() {
    acra_install_detect_os
    acra_install_parse_args "$@"
    acra_install_check
    acra_install_main
    acra_install_post
}

acra_install "$@"
