#!/usr/bin/env bash

print_warning () { printf "\E[33m%s Warning: $@ %s\e[0m\n" ;}
print_error () { printf "\E[31m%s Error: $@ %s\e[0m\n" ;}
print_info () { printf "\E[36m%s Info: $@ %s\e[0m\n" ;}
print_ok () { printf "\E[35m%s OK: $@ %s\e[0m\n" ;}
fatal () { print_error "$@" ; exit 1 ;}
print_var () { for vp in $@ ; do print_info "${vp} = ${!vp}" ; done ;}

[[ $(id -u) = 0 ]] && fatal "Do not run this script as root!"

export ALVR_CONFIG_PATH="$HOME/.config/alvr"
export STEAM_PATH="$HOME/.local/share/Steam"
export STEAMVR_TOOLSDIR="$STEAM_PATH/steamapps/common/SteamVR"
export VRBINDIR="$STEAMVR_TOOLSDIR/bin"
export VRMONITOR="$VRBINDIR/linux64/vrmonitor"
export VRC_LAUNCHER="$VRBINDIR/linux64/vrcompositor-launcher"
export STEAMVR_VRSETTINGS="$STEAM_PATH/config/steamvr.vrsettings"

if [[ $XDG_SESSION_TYPE == "wayland" ]] ; then
    export QT_QPA_PLATFORM="xcb"
    export WAYLAND_DISPLAY=''
fi

yad_command="yad --no-wrap --width=400 --height=50 --borders=15
            --window-icon=/usr/share/icons/hicolor/128x128/apps/alvr.png"

yad_info () {
    print_info "$@"
    $yad_command --title "INFO" --text "$@" --button="OK" 2>/dev/null
}

yad_error () {
    print_error "$@"
    $yad_command --title "ERROR" --text "$@" --button="OK" 2>/dev/null
}

yad_question () {
    $yad_command --title "CHOISES" --text "$@" \
    --button="CANCEL":1 --button="OK":0 2>/dev/null
}

notify_send () {
    gdbus call --session --dest org.freedesktop.Notifications \
    --object-path /org/freedesktop/Notifications \
    --method org.freedesktop.Notifications.Notify \
    "ALVR" 0 "/usr/share/icons/hicolor/128x128/apps/alvr.png" \
    "$1" "$2" "[]" "{}" "$3" &>/dev/null
}

adb_functions () {
    PC_ALVR_VERSION=$(rpm -q 'alvr' | awk -F- '{print $2}')
    print_var PC_ALVR_VERSION

    while read line ; do
        [[ $line =~ device$ ]] && DEVICES+=(${line//device/})
    done <<< $(adb devices)

    if [[ -z ${DEVICES[@]} ]] ; then
        print_info "USB devices not found."
    else
        print_info "found devices: ${DEVICES[@]}"

        get_device_info () {
            adb_command="adb -s $1"

            DEVICE="$1"
            DEVICE_IP="$($adb_command shell ip addr show wlan0 | grep "inet " | awk '{print $2}' | awk -F'/' '{print $1}')"
            MODEL="$($adb_command shell getprop ro.product.model)"
            MANUFACTURER="$($adb_command shell getprop ro.product.manufacturer)"
            INSTALLED_ALVR="$($adb_command shell dumpsys package alvr.client.stable | grep "versionName=" | awk -F= '{print $2}')"
            [[ -z $INSTALLED_ALVR ]] && INSTALLED_ALVR="Not installed"
            export DEVICE MODEL MANUFACTURER INSTALLED_ALVR

            echo " ##################################"
            print_var DEVICE MODEL MANUFACTURER INSTALLED_ALVR DEVICE_IP
            echo " ##################################"
        }

        #TODO: check all devices
        get_device_info ${DEVICES[0]}

        if [[ $INSTALLED_ALVR != $PC_ALVR_VERSION ]] \
        && yad_question "\nOn device: $MANUFACTURER $MODEL
    ALVR version not installed $PC_ALVR_VERSION.
    \n\nWant to download and install?"
        then
            print_info "We are starting to download the client for the virtual reality helmet..."

            APK_URL="https://github.com/alvr-org/ALVR/releases/download/v$PC_ALVR_VERSION/alvr_client_android.apk"
            APK_FILE="/tmp/alvr_client_$PC_ALVR_VERSION.apk"

            set -o pipefail
            curl -f -# -A 'Mozilla/5.0 (compatible; Konqueror/2.1.1; X11)' \
            -H 'Cache-Control: no-cache, no-store' -H 'Pragma: no-cache' \
            -L "$APK_URL" -o "$APK_FILE" 2>&1 | tr '\r' '\n' \
            | sed -ur 's|[# ]+||g;s|100||g;s|.*=.*||g;s|.*|#Downloading at &\n&|g' | \
            $yad_command --progress --text="Downloading ${APK_FILE//*\//}" --auto-close \
            --no-escape --auto-kill --no-buttons --title "Downloading"
            if [[ "${PIPESTATUS[0]}" == 0 ]] ; then
                print_ok "Done."
                print_info "Installing alvr_client_$PC_ALVR_VERSION.apk to $MANUFACTURER $MODEL..."
                if adb -s "$DEVICE" install "$APK_FILE" ; then
                    yad_info "Installation completed successfully."
                else
                    yad_error "An error occurred during installation."
                fi
            else
                yad_error "An error occurred while downloading."
            fi
            [[ -f "$APK_FILE" ]] && rm -f "$APK_FILE"
        fi

        for port in 9943 9944 ; do
            if $adb_command forward tcp:$port tcp:$port 1>/dev/null ; then
                notify_send "$MANUFACTURER successfully connected." \
                "Use IP: 127.0.0.1 for connection via USB." 10000
                print_ok "$adb_command forward tcp:$port tcp:$port"
            else
                print_error "$adb_command forward tcp:$port tcp:$port"
            fi
        done

        if [[ -f "$HOME/.android/adbkey.pub" ]]
        then export ADB_VENDOR_KEYS="$HOME/.android/adbkey.pub"
        fi
        echo " ##################################"
    fi
}

force_kill_vr () {
    for kill in vrserver vrmonitor vrwebhelper vrcompositor vrdashboard alvr_dashboard ; do
        kill_pid=$(ps aux | grep $kill | grep -v grep | awk '{print $2}')
        [[ -n $kill_pid ]] && kill -n 9 $kill_pid
    done
}

reset_alvr_settings () {
    if [[ -d "$HOME/.config/alvr" ]]
    then rm -r "$HOME/.config/alvr"
    fi
}

check_steamvr () {
    if [[ ! -f "/usr/bin/steam" ]] || [[ ! -f "$VRMONITOR" ]] ; then
        echo "Instructions: https://www.altlinux.org/ALVR" \
        | $yad_command --show-uri --title "ERROR" --text-info \
        --text="You need to install <b>Steam</b> and <b>SteamVR</b>." --button="EXIT" 2>/dev/null
        exit 1
    fi

    for vdf in "$STEAM_PATH/userdata/"*"/config/localconfig.vdf" ; do
        unset LINE_N LINE_R
        while read line ; do
            [[ $line =~ "LastPlayed" ]] && LINE_N=${line//-*/}
            [[ $line =~ "LaunchOptions" && ! $line =~ "vrmonitor" ]] && LINE_R=${line//-*/}
        done <<< $(grep -n -A2 "\"250820\"$" "$vdf")

        RUN_STEAM="0"
        if [[ -n $LINE_N || -n $LINE_R ]] \
        && pgrep -i steam &>/dev/null ;
        then
            kill -s SIGTERM $(pgrep -a steam) &>/dev/null
            notify_send "Restart Steam." \
            "Please wait." 5000
            while pgrep -i steam &>/dev/null ; do
                sleep 0.1
            done
            RUN_STEAM="1"
        fi

        if [[ -n $LINE_N ]] ; then
            sed -i "${LINE_N}i \"LaunchOptions\" \"$VRBINDIR/vrmonitor.sh %command%\"" "$vdf"
        elif [[ -n $LINE_R ]] ; then
            sed -ie "${LINE_R}d" "$vdf"
            sed -i "${LINE_R}i \"LaunchOptions\" \"$VRBINDIR/vrmonitor.sh %command%\"" "$vdf"
        fi
        [[ $RUN_STEAM == "1" ]] && steam -silent &
    done
}

start_alvr () {
    if pactl info | grep -i "pipewire" ; then
        print_info "PipeWire in use. OK."
    else
        yad_error "PipeWire is not installed, or not used.\nSee: https://www.altlinux.org/Pipewire"
        exit 1
    fi

    if [[ -f "/usr/share/vulkan/icd.d/nvidia_icd.json" ]] ; then
        VK_ADD_DRIVER_FILES="$(realpath /usr/share/vulkan/icd.d/nvidia_icd.json)"
        export VK_ADD_DRIVER_FILES
    fi
    export LIBGL_DRIVERS_PATH="/usr/lib/X11/modules/dri:/usr/lib64/X11/modules/dri"
    export PATH+="$PATH:/sbin"

    if [[ ! "$(getcap "$VRC_LAUNCHER")" == *"cap_sys_nice"* ]]
    then pkexec setcap CAP_SYS_NICE=eip "$VRC_LAUNCHER"
    fi

    restore_steamvr_vrsettings () {
        if [[ -f "$STEAMVR_VRSETTINGS.bak" ]] ; then
            [[ -f "$STEAMVR_VRSETTINGS" ]] && rm -f "$STEAMVR_VRSETTINGS"
            mv -f "$STEAMVR_VRSETTINGS.bak" "$STEAMVR_VRSETTINGS"
        fi
    }
    trap "restore_steamvr_vrsettings" EXIT

    if [[ -f "$STEAMVR_VRSETTINGS.bak" ]] && [[ -f "$STEAMVR_VRSETTINGS" ]]
    then rm -f "$STEAMVR_VRSETTINGS"
    elif [[ ! -f "$STEAMVR_VRSETTINGS.bak" ]] && [[ -f "$STEAMVR_VRSETTINGS" ]]
    then mv -f "$STEAMVR_VRSETTINGS" "$STEAMVR_VRSETTINGS.bak"
    fi

    if [[ -f "$STEAM_PATH/config/vrserver_crash_timestamp.txt" ]]
    then rm -f "$STEAM_PATH/config/vrserver_crash_timestamp.txt"
    fi

    if [[ ! -d  "$ALVR_CONFIG_PATH" ]]
    then mkdir -p "$ALVR_CONFIG_PATH"
    fi

    SESSION_JSON="$ALVR_CONFIG_PATH/session.json"
    if [[ ! -f "$SESSION_JSON" ]] ; then
        cp "/usr/lib64/alvr/default_settings.json" "$SESSION_JSON"
    else
        if ! grep "\"server_version\": \"$PC_ALVR_VERSION\"" "$SESSION_JSON" ; then
            rm -f "$SESSION_JSON"
            cp "/usr/lib64/alvr/default_settings.json" "$SESSION_JSON"
        fi
    fi

    if [[ -n "$DEVICE_IP" ]]
    then echo "$DEVICE_IP" > "$ALVR_CONFIG_PATH/vrclient_ip"
    elif [[ -f "$ALVR_CONFIG_PATH/vrclient_ip" ]]
    then DEVICE_IP=$(cat "$ALVR_CONFIG_PATH/vrclient_ip")
    fi

    if [[ -n "$DEVICE_IP" ]] ; then
        MANUAL_IP_N=$(grep -n "\"wifi.client\"" "$SESSION_JSON" | awk -F: '{print $1}')
        if [[ -n $MANUAL_IP_N ]] \
        && [[ "$(sed -n $((MANUAL_IP_N + 4))p "$SESSION_JSON")" =~ ([0-9]+.[0-9]+.[0-9]+.[0-9]+) ]]
        then sed -i "$((MANUAL_IP_N + 4)) s/\".*\"/\"$DEVICE_IP\"/" "$SESSION_JSON"
        fi
    fi

    alvr_dashboard
}

case "$1" in
   --client|-c) adb_functions ;;
     --kill|-k) force_kill_vr ;;
    --reset|-r)
                force_kill_vr
                reset_alvr_settings
                check_steamvr
                adb_functions
                start_alvr
                ;;
             *)
                check_steamvr
                adb_functions
                start_alvr
                ;;
esac
