#!/bin/bash
PATH=/usr/bin:/usr/sbin:/usr/share/rphone-dev-init:/bin:/sbin

LOG_FILE="/var/log/rphone-setup.log"
exec > >(tee -a "$LOG_FILE") 2>&1

PACKAGES="virtualbox docker unzip gzip curl sshpass procps-ng qemu-user-binfmt qemu-aarch64-static"

CODE_REPO="http://packages.microsoft.com:80/yumrepos/vscode/"
CODIUM_REPO="https://abf-downloads.rosa.ru/import_personal/container/5489087/x86_64/main/release/"

VSIX='https://portal.rosa.ru/~MZJWm'
RPHONE_OVA='https://portal.rosa.ru/~nUESh'

VSIX_DEPS="ms-vscode.cpptools bbenoist.qml"

export TEXTDOMAINDIR=/usr/share/locale
export TEXTDOMAIN=rphone-dev-init

DOCURL="https://developer.rosa.ru/development/vs-code/installyator-pod-fresh"

_() {
    gettext "$1"
}

FINAL_TEXT="$(_ "Read the fine manual:") ${DOCURL}
$(_ "Note: To apply all changes, user needs to reboot the system")"

show_help() {
    if [ -z "$LANG" ] || [ "$LANG" != "ru_RU.UTF-8" ] ; then
        cat << EOF
Usage: $0 [OPTION] [IDE]

Install development environment for R-Phone development.

Options:
  --help          Show this help message and exit

IDE options:
  code|vscode     Visual Studio Code (default)
  codium|vscodium VS Codium

This script will:
1. Install the specified IDE and required packages
2. Set up Docker and VirtualBox
3. Download and install VSIX extensions
4. Configure user permissions for development tools
5. Manual page (ru): $DOCURL

Examples:
  $0              # Install with Visual Studio Code
  $0 codium       # Install with VS Codium
EOF
    else
        cat << EOF
Использование: $0 [OPTION] [IDE]

Установка среды разработки для R-Phone.

Опции:
  --help          Показать эту справку и выйти

Варианты IDE:
  code|vscode     Visual Studio Code (по умолчанию)
  codium|vscodium VS Codium

Этот скрипт выполнит:
1. Установку выбранной IDE и необходимых пакетов
2. Настройку Docker и VirtualBox
3. Загрузку и установку VSIX расширений
4. Настройку прав пользователя для инструментов разработки
5. Страница руководства (ru): $DOCURL

Примеры:
  $0              # Установка с Visual Studio Code
  $0 codium       # Установка с VS Codium
EOF
fi

}

download_file() {
    local url="$1"
    local file="$2"
    local cookie_file="/tmp/cookies_$$.txt"
    local user_agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36"

    # Получаем ссылку для скачивания
    download_path=$(curl -s -L -c "$cookie_file" -A "$user_agent" "$url" 2>/dev/null | \
        grep -o 'docs/pub/[^"]*download[^"]*token=[^"]*' | head -1)

    [ -z "$download_path" ] && echo_exit "$(_ "Can not get download link")" ${LINENO}
    download_url="https://portal.rosa.ru/$download_path"

    echo "$(_ "Starting download:")  $file: $download_url" >&2

    try=1
    while [ $try -lt 5  ] ; do
        curl_exit_code=0
        curl -L -b "$cookie_file" \
            -A "$user_agent" \
            --retry 10 \
            --retry-delay 30 \
            --retry-max-time 3600 \
            --connect-timeout 300 \
            --max-time 0 \
            --max-filesize 5000000000 \
            -C - \
            --progress-bar \
            --ssl-allow-beast \
            --ciphers DEFAULT@SECLEVEL=1 \
            -o "$file" \
            "$download_url" 1>&2 || curl_exit_code=$?
        [[ $curl_exit_code -eq 0 ]] && break
        sleep 5
        try=$(( try + 1 ))
        echo "$(_ attempt: )"$try >&2
    done

    # Анализируем код возврата curl
    case $curl_exit_code in
        0)
            if [ -f "$file" ] && [ -s "$file" ]; then
                echo "$(_ "File successfully downloaded:") $file" >&2
                echo "$file"
                rm -f "$cookie_file"
                return 0
            else
                echo_exit "$(_ "Downloaded file is empty or missing:") $file" ${LINENO}
            fi
            ;;
        *)
            echo_exit "$(_ "Download $file failed with curl error code:") $curl_exit_code" ${LINENO}
            ;;
    esac
}

action () {
    echo -e "\n==> $1"
    ACTION=$1
}

echo_exit(){
    echo -n "${ACTION}: "
    echo "$1" 1>&2
    [ "$2" ] && exit "$2"
    exit 0
}

get_extension() {
    EXTENSION_ID="$1"
    PUBLISHER="$( echo $1 |cut -f1 -d '.')"
    EXTENSION_NAME="$( echo $1 |cut -f2 -d '.')"

    URL="https://marketplace.visualstudio.com/_apis/public/gallery/publishers/$PUBLISHER/vsextensions/$EXTENSION_NAME/latest/vspackage"

    curl -L -H "Accept: application/octet-stream" \
     -H "User-Agent: VSCode" \
     "$URL" -o "$EXTENSION_ID.xxx"

    # Проверяем что за файл
    if file "$EXTENSION_ID.xxx" | grep -q "Zip archive"; then
        mv "$EXTENSION_ID.xxx" "$EXTENSION_ID.vsix"
    elif
        file "$EXTENSION_ID.xxx" |grep -q gzip ; then
        mv $EXTENSION_ID.xxx $EXTENSION_ID.gz
        gunzip $EXTENSION_ID.gz
        mv $EXTENSION_ID $EXTENSION_ID.vsix
    fi
}

check_space(){
    rootdev=$(df / | tail -n1 |cut -f1 -d ' ')
    rootsize=$(( $(df -k / | tail -n1 |awk '{print $4}') / 1000 / 1000 ))
    homedev=$(df /home/$1 | tail -n1 |cut -f1 -d ' ')
    echo "$(_ "Available space in root:") ${rootsize}GB"
    if [ "$rootdev" == "$homedev" ] ; then
      if [ $rootsize -lt 25 ] ; then
          echo "Not enouth disk space"
          exit 1
      fi
    else
      homesize=$(( $(df -k /home | tail -n1 |awk '{print $4}') / 1000 / 1000 ))
      echo "$(_ "Available space in home:") ${homesize}GB"
      if [ "$rootsize" -lt 10 ] || [ "$homesize" -lt 15 ] ; then
              echo "$(_ "Not enough disk space"), (home >= 15GB + root >= 10GB) "
              exit 1
      fi
    fi
    echo
}

if [ "$1" = "--help" ] || [ "$1" = "-h" ]; then
    show_help
    exit 0
fi

action "$(_ "Check and settings")"
    [ $(id -un) == 'root' ] || echo_exit "Must be root" ${LIONENO}

    case "${1:-auto}" in
        code|vscode)
            IDE=code; IDE_REPO=$CODE_REPO ;;
        codium|vscodium)
            IDE=codium; IDE_REPO=$CODIUM_REPO ;;
        auto|"")
            if rpm -q code >/dev/null 2>&1; then
                IDE=code; IDE_REPO=$CODE_REPO
            elif rpm -q codium >/dev/null 2>&1; then
                IDE=codium; IDE_REPO=$CODIUM_REPO
            else
                IDE=code; IDE_REPO=$CODE_REPO
            fi
            ;;
        *) echo_exit "$(_  "Unknown parameter:") $1" ;;
    esac
    PACKAGES="$PACKAGES $IDE"
    check_space

    USER_NAME=$(xuserrun whoami)
    USER_HOME=$(xuserrun set |grep -w 'HOME=' | cut -f2 -d=)

    pushd "$USER_HOME"

action "$(_  "Install packages")"
    dnf refresh
    yes | dnf install -y $PACKAGES --repofrompath code,$IDE_REPO --nogpgcheck \
        || echo_exit "$(_  "Dnf install failed. Check network connection and try again.")" ${LINENO}
    dnf update -y $IDE --repofrompath code,$IDE_REPO --nogpgcheck

action "$(_  "Setup user groups")"
    usermod -aG docker $USER_NAME || echo_exit "$(_ "Failed: add user to the docker group")" ${LINENO}
    usermod -aG vboxusers $USER_NAME || echo_exit "$(_ "Failed: add user to the vboxusers group")" ${LINENO}

action "$(_ "Download vsix rosa vscode extension, ova virtual machine container")"
    RPHONE_OVA=$(download_file $RPHONE_OVA "R-PhoneEmulatorx86.ova")
    [ -f ./"$RPHONE_OVA" ] || echo_exit "$(_  "failed: download ova image"): $RPHONE_OVA" ${LINENO}
    VSIX=$(download_file $VSIX "vscode-rosa.vsix")
    [ -f ./"$VSIX" ] ||echo_exit "$(_ "failed: download rosa vscode extension"): $VSIX" ${LINENO}

action "$(_ "Generate ssh keys")"
    if [ ! -f $USER_HOME/.ssh/vscode-rosa.pub ]; then
        xuserrun ssh-keygen -t rsa -b 4096 -f ${USER_HOME}/.ssh/vscode-rosa -N "" -q
    fi

action "$(_  "Import Rosa virtual machine image")"
    xuserrun VBoxManage import $(realpath $(basename $RPHONE_OVA)) --vsys 0 --group "/Rosa Virtual Devices"
    [ $? -ne 0 ] && echo_exit "$(_  "failed: import $(basename $RPHONE_OVA)")" ${LINENO}

action "$(_ "Setup ssh keys")"
    # First start VM is needed for VirtualBox GUI
    if ! pgrep VirtualBox ; then
        xuserrun VirtualBox &
        sleep 3
        NEWPID=$(pgrep VirtualBox)
    fi
    xuserrun VBoxManage startvm "R-Phone Emulator x86" --type headless

    (
    sleep 40

    MAX_ATTEMPTS=6
    attempt=1
    while [ $attempt -le $MAX_ATTEMPTS ]; do
        if xuserrun sshpass -p 'rosa' ssh-copy-id -i ${USER_HOME}/.ssh/vscode-rosa -p 23164 -o ConnectTimeout=10 emulator@127.0.0.1 2>/dev/null; then
            echo "$(_ "SSH keys successfully configured")"
            if xuserrun ssh -i ${USER_HOME}/.ssh/vscode-rosa -p 23164 -o ConnectTimeout=10 -o StrictHostKeyChecking=no emulator@127.0.0.1 "sync" 2>/dev/null ; then
               echo "$(_ "SSH keys check: successfull")"
               xuserrun ssh -i ${USER_HOME}/.ssh/vscode-rosa -p 23164 -o ConnectTimeout=10 -o StrictHostKeyChecking=no emulator@127.0.0.1 "poweroff" 2>/dev/null
               POWEROFFSENT='yes'
               break
            fi
        fi
        echo "${attempt}:  $(_ "failed, retrying in 10 seconds...")"
        sleep 10
        attempt=$((attempt + 1))
    done
    [ "$POWEROFFSENT" ] || xuserrun VBoxManage controlvm "R-Phone Emulator x86" acpipowerbutton

    for i in {1..10}; do
            if ! xuserrun VBoxManage showvminfo "R-Phone Emulator x86" | grep -q "running"; then
                echo "$(_ "VM shut down successfully")"
                break
            fi
            sleep 3
    done

    if xuserrun VBoxManage showvminfo "R-Phone Emulator x86" | grep -q "running"; then
        echo "$(_ "VM still running, forcing poweroff...")"
        xuserrun VBoxManage controlvm "R-Phone Emulator x86" poweroff &
    fi
    ) &

    SSH_SETUP_PID=$!

action "$(_ "Setup docker")"
    systemctl enable docker
    systemctl start docker || echo_exit "$(_ "Failed: docker daemon start")" ${LINENO}

    docker pull hub.rosa.ru/rosamobile/rosa2021.15-mobile-package-builder-arm64:latest || \
        echo_exit "$(_ "failed: pull arm Rosa docker image")" ${LINENO}
    docker pull hub.rosa.ru/rosamobile/rosa2021.15-mobile-package-builder-x86_64:latest || \
        echo_exit "$(_ "failed: pull x86_64 Rosa docker image")" ${LINENO}
    docker run --rm --privileged multiarch/qemu-user-static --reset -p yes

action "$(_  "Get and install vscode additional extensions")"
    for a in $VSIX_DEPS ; do
        if [ "$IDE" == 'code' ] ; then
            xuserrun $IDE --install-extension $a || echo_exit "$(_  "Install extension failed:") $a" ${LINENO}
        else
            get_extension $a
            xuserrun $IDE --install-extension ${a}.vsix || echo_exit "$(_  "Install extension failed:") $a" ${LINENO}
        fi
    done

action "$(_ "Install rosa vscode extension")"
    timeout 300 xuserrun $IDE --password-store=basic --install-extension $(basename $VSIX)
    popd

    if [ $? -eq 124 ]; then
        echo -e "\n${ACTION}:"
        echo "$(_  "ERROR: Installation timeout exceeded (5 minutes). The extension installation took too long.")"
        echo "$(_ "Please check your internet connection and try to install:") $(pwd)/$(basename $VSIX)"
        echo "$(_ "in graphical interface") $IDE"
        echo
        echo "$FINAL_TEXT"
        exit ${LINENO}
    fi

if kill -0 $SSH_SETUP_PID 2>/dev/null; then
    sleep 3
    action "$(_  "Waiting ssh setup subprocess")"
        while kill -0 $SSH_SETUP_PID 2>/dev/null; do
            sleep 5
        done
fi

[ -n "$NEWPID" ] && kill "$NEWPID" 2>/dev/null

echo
echo "1. $(_ "All required software has been successfully installed")"
echo "2. $USER_NAME $(_ "has been added to docker and vboxusers groups")"
echo "3. $(_ "R-phone x86_64 and ARM Docker build containers have been pulled")"
echo "4. $(_ "R-Phone virtual machine OVA container has been downloaded to") $USER_HOME"
echo "5. $(_ "R-Phone virtual machine has been imported into VirtualBox emulator")"
echo
echo "$FINAL_TEXT"

