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

origin='github.com/bottlesdevs/bottles'
min_cpak_version='2.14.13'
state_home="${XDG_STATE_HOME:-$HOME/.local/state}/bottles-cpak"
umask 077
mkdir -p "$state_home"
log="$state_home/launch.log"

usage() {
    cat <<'USAGE'
Usage: bottles-cpak [run [ARGS...] | install | update | remove | doctor | help]
  run       Install Bottles on first use, then launch it (default)
  install   Install the official Bottles CPak package
  update    Update Bottles through CPak
  remove    Remove Bottles through CPak (user data is preserved)
  doctor    Check CPak host requirements
USAGE
}

show_error() {
    printf 'Bottles (CPak): %s\nSee %s\n' "$1" "$log" >&2
    if [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]] && command -v zenity >/dev/null 2>&1; then
        zenity --error --title='Bottles' --width=500 \
            --text="$1\n\nLog: $log" >/dev/null 2>&1 || :
    fi
}

if [[ ${1:-} == help || ${1:-} == -h || ${1:-} == --help ]]; then
    usage
    exit 0
fi

if ! command -v cpak >/dev/null 2>&1; then
    show_error 'CPak is not installed.'
    exit 127
fi

if ! version_output="$(cpak --version 2>&1)"; then
    printf '%s\n' "$version_output" >> "$log"
    show_error 'Cannot determine the installed CPak version.'
    exit 1
fi
version="$(printf '%s\n' "$version_output" | grep -Eo '[0-9]+\.[0-9]+\.[0-9]+' | head -n 1 || true)"
if [[ -z "$version" ]] || [[ "$(printf '%s\n' "$min_cpak_version" "$version" | sort -V | head -n 1)" != "$min_cpak_version" ]]; then
    show_error "CPak $min_cpak_version or newer is required. Detected: ${version:-unknown}."
    exit 1
fi

installed() {
    local inventory
    inventory="$(cpak list --json 2>> "$log")" || return 2
    grep -Fq "$origin" <<< "$inventory"
}

install_bottles() {
    local status=0
    installed || status=$?
    if (( status == 0 )); then
        return 0
    fi
    if (( status != 1 )); then
        show_error 'Unable to check CPak installed applications.'
        return 1
    fi

    printf '[%s] Installing Bottles through CPak\n' "$(date -Is)" >> "$log"
    status=0
    if [[ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]] && command -v zenity >/dev/null 2>&1; then
        cpak install --yes -b main "$origin" 2>&1 \
            | tee -a "$log" \
            | sed -u 's/^/# /' \
            | zenity --progress --pulsate --auto-close --no-cancel \
                --title='Bottles' --text='Installing Bottles for this user' --width=500 \
            || status=${PIPESTATUS[0]}
    else
        cpak install --yes -b main "$origin" 2>&1 | tee -a "$log" \
            || status=${PIPESTATUS[0]}
    fi

    if (( status != 0 )); then
        show_error "Bottles installation failed (exit $status)."
        return 1
    fi
    if ! installed; then
        show_error 'CPak returned successfully without installing Bottles.'
        return 1
    fi
}

run_bottles() {
    local status=0
    cpak run "$origin" bottles "$@" 2>&1 | tee -a "$log" || status=${PIPESTATUS[0]}
    if (( status != 0 )); then
        show_error "Bottles could not start (exit $status)."
    fi
    return "$status"
}

command="${1:-run}"
if (( $# > 0 )); then shift; fi
case "$command" in
    run)
        install_bottles || exit 1
        if command -v bottles-office-experimental >/dev/null 2>&1; then
            if ! bottles-office-experimental install; then
                printf '%s\n' 'Office setup did not complete. Opening Bottles normally.' >&2
            fi
        fi
        run_bottles "$@"
        ;;
    install)
        if (( $# > 0 )); then usage >&2; exit 64; fi
        install_bottles
        ;;
    update|remove|doctor)
        if (( $# > 0 )); then usage >&2; exit 64; fi
        status=0
        case "$command" in
            update) cpak update "$origin" 2>&1 | tee -a "$log" || status=${PIPESTATUS[0]} ;;
            remove) cpak remove "$origin" 2>&1 | tee -a "$log" || status=${PIPESTATUS[0]} ;;
            doctor) cpak doctor 2>&1 | tee -a "$log" || status=${PIPESTATUS[0]} ;;
        esac
        exit "$status"
        ;;
    *)
        usage >&2
        exit 64
        ;;
esac
