#!/usr/bin/env bash
set -euo pipefail

origin='github.com/bottlesdevs/bottles'
runner="$(find "${BOTTLES_SODA_RUNNERS_ROOT:-/usr/libexec/bottles-soda-experimental}" -mindepth 1 -maxdepth 1 -type d -name 'soda-*-experimental' -printf '%f\n' 2>/dev/null | LC_ALL=C sort -V | tail -n 1)"
[[ -n "$runner" ]] || { echo 'No packaged experimental Soda runner found' >&2; exit 1; }
data_home="${XDG_DATA_HOME:-$HOME/.local/share}"
state_home="${XDG_STATE_HOME:-$HOME/.local/state}/bottles-office-experimental"
bottles_home="$data_home/bottles"
log="$state_home/install.log"
helper="$bottles_home/.office-experimental-installer.py"
word="$bottles_home/bottles/Office/drive_c/Program Files/Microsoft Office/root/Office16/WINWORD.EXE"

installed() {
    cpak list --json | grep -Fq "$origin"
}

show_error() {
    printf '%s\n' "$1" >&2
    if [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]] && command -v zenity >/dev/null 2>&1; then
        zenity --error --title='Microsoft 365 setup' --width=480 --text="$1" >/dev/null 2>&1 || :
    fi
}

select_edition() {
    case "${1:-}" in
        business|enterprise)
            printf '%s\n' "$1"
            ;;
        '')
            if [[ -s "$state_home/edition" ]]; then
                cat "$state_home/edition"
                return
            fi
            if [[ -z "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]] || ! command -v zenity >/dev/null 2>&1; then
                show_error 'Choose an edition: bottles-office-experimental install business|enterprise'
                return 1
            fi
            local selected
            selected="$(zenity --list --title='Microsoft 365 Experimental' \
                --text='Choose the edition matching your Microsoft 365 license' \
                --column='Edition' --column='Value' --hide-column=2 --print-column=2 \
                'Microsoft 365 Apps for business' business \
                'Microsoft 365 Apps for enterprise' enterprise \
                --width=540 --height=270)" || return 1
            case "$selected" in
                business|enterprise) printf '%s\n' "$selected" ;;
                *) return 1 ;;
            esac
            ;;
        *)
            show_error 'The Office edition must be business or enterprise.'
            return 2
            ;;
    esac
}

prepare() {
    if ! installed; then
        echo 'Installing official Bottles through CPak' >> "$log"
        local status=0
        if [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]] && command -v zenity >/dev/null 2>&1; then
            set +e
            timeout --signal=TERM --kill-after=20s 1200s \
                cpak install --yes -b main "$origin" 2>&1 \
                | tee -a "$log" \
                | sed -u 's/^/# /' \
                | zenity --progress --pulsate --auto-close --no-cancel \
                    --title='Installing Bottles' \
                    --text='Installing official Bottles through CPak' --width=520
            status=${PIPESTATUS[0]}
            set -e
        else
            set +e
            timeout --signal=TERM --kill-after=20s 1200s \
                cpak install --yes -b main "$origin" >> "$log" 2>&1
            status=$?
            set -e
        fi
        if (( status != 0 )); then
            show_error "Bottles installation failed (exit $status). See $log"
            return "$status"
        fi
        if ! installed; then
            show_error "Bottles is still not installed in CPak. See $log"
            return 1
        fi
    fi

    if [[ ! -x "$bottles_home/runners/$runner/bin/wine" ]]; then
        printf 'Importing installed %s runner\n' "$runner" >> "$log"
        if ! bottles-soda-import >> "$log" 2>&1; then
            show_error "Soda runner import failed. See $log"
            return 1
        fi
    fi
    if [[ ! -x "$bottles_home/runners/$runner/bin/wine" ]]; then
        show_error "The expected runner ($runner) is missing. See $log"
        return 1
    fi
}

install_office() {
    local edition="$1" status=0
    install -Dm0644 "${BOTTLES_OFFICE_HELPER:-/usr/share/bottles-office-experimental/office-install.py}" "$helper"
    printf '[%s] Installing Microsoft 365 (%s)\n' "$(date -Is)" "$edition" >> "$log"
    if [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]] && command -v zenity >/dev/null 2>&1; then
        set +e
        timeout --signal=TERM --kill-after=20s 7200s \
            cpak run "$origin" @python3 "$helper" "$edition" "$runner" 2>&1 \
            | tee -a "$log" \
            | sed -u -e '/^PROGRESS [0-9]/!s/^/# /' -e 's/^PROGRESS //' \
            | zenity --progress --pulsate --auto-close --no-cancel \
                --title='Microsoft 365 setup' --text='Installing experimental Microsoft 365' --width=520
        status=${PIPESTATUS[0]}
        set -e
    else
        set +e
        timeout --signal=TERM --kill-after=20s 7200s \
            cpak run "$origin" @python3 "$helper" "$edition" "$runner" >> "$log" 2>&1
        status=$?
        set -e
    fi
    if (( status != 0 )); then
        show_error "Microsoft 365 setup failed (exit $status). See $log"
        return "$status"
    fi
    if [[ ! -f "$word" ]]; then
        show_error "Office setup finished without installing Word. See $log"
        return 1
    fi
    printf '%s\n' "$edition" > "$state_home/edition"
    printf '[%s] Office installed\n' "$(date -Is)" >> "$log"
}

main() {
    if [[ "$(id -u)" == 0 ]]; then
        show_error 'This installer must run as your desktop user, not as root.'
        return 1
    fi
    umask 077
    mkdir -p "$state_home"
    exec 9>"$state_home/lock"
    flock 9

    case "${1:-install}" in
        install)
            if [[ -f "$word" && -s "$state_home/edition" ]]; then
                return 0
            fi
            local edition
            edition="$(select_edition "${2:-}")" || return 1
            if [[ -s "$state_home/edition" && "$(<"$state_home/edition")" != "$edition" ]]; then
                show_error 'An Office bottle already exists with another edition.'
                return 1
            fi
            if [[ -s "$state_home/requested-edition" && "$(<"$state_home/requested-edition")" != "$edition" ]]; then
                show_error 'A previous Office installation used another edition. Complete it before changing editions.'
                return 1
            fi
            printf '%s\n' "$edition" > "$state_home/requested-edition"
            prepare || return 1
            install_office "$edition"
            ;;
        status)
            if [[ -f "$word" ]]; then
                printf 'Microsoft Word present: %s\n' "$word"
            else
                printf 'Microsoft Office is not installed. Log: %s\n' "$log"
            fi
            ;;
        *)
            printf '%s\n' 'Usage: bottles-office-experimental [install [business|enterprise] | status]' >&2
            return 2
            ;;
    esac
}
main "$@"
