#!/usr/bin/env bash
set -Eeuo pipefail
export TEXTDOMAIN=${TEXTDOMAIN:-eczos-gaming}
export TEXTDOMAINDIR=${TEXTDOMAINDIR:-/usr/share/locale}
_() { gettext "$1"; }

usage() {
    cat <<EOF
$(_ 'Usage: eczos-gaming COMMAND')

  doctor [--json]  $(_ 'Check GPU, Vulkan, 32-bit drivers and runtimes')
  status           $(_ 'Same as doctor')
  check-ready      $(_ 'Succeed only when Proton gaming is fully ready')
  manage           $(_ 'Show the status graphically')
  runtime-info     $(_ 'Show the pinned UMU runtime information')
EOF
}

collect_status() {
    gpu=$(lspci -nnk 2>/dev/null | awk '
        /VGA compatible controller|3D controller|Display controller/ {
            if (seen++) printf "; ";
            sub(/^[^ ]+ /, ""); printf "%s", $0; in_gpu=1; next
        }
        in_gpu && /Kernel driver in use:/ {
            sub(/^[[:space:]]+/, ""); printf " (%s)", $0; in_gpu=0
        }
        END {print ""}' | head -c 2000)
    [[ -n "$gpu" ]] || gpu=$(_ 'Unknown graphics adapter')

    vulkan_summary=''
    if command -v vulkaninfo >/dev/null 2>&1; then
        vulkan_summary=$(timeout 15s vulkaninfo --summary 2>&1 || true)
    fi
    vulkan_devices=$(awk -F= '/deviceName[[:space:]]*=/{gsub(/^[[:space:]]+|[[:space:]]+$/, "", $2); if (out) out=out "; "; out=out $2} END{print out}' <<<"$vulkan_summary")
    [[ -n "$vulkan_devices" ]] || vulkan_devices=$(_ 'No Vulkan device found')

    hardware_vulkan=false
    if grep -Eq 'PHYSICAL_DEVICE_TYPE_(DISCRETE|INTEGRATED|VIRTUAL)_GPU' <<<"$vulkan_summary"; then
        hardware_vulkan=true
    fi
    software_vulkan=false
    if grep -Eiq 'llvmpipe|lavapipe|PHYSICAL_DEVICE_TYPE_CPU' <<<"$vulkan_summary"; then
        software_vulkan=true
    fi

    vulkan_32=false
    if [[ -e /usr/lib/i386-linux-gnu/libvulkan.so.1 ]] && \
        find /usr/lib/i386-linux-gnu -maxdepth 1 -type f -name 'libvulkan_*.so' \
        -print -quit 2>/dev/null | grep -q .; then
        vulkan_32=true
    fi

    umu=false
    command -v umu-run >/dev/null 2>&1 && umu=true
    gamemode=false
    command -v gamemoderun >/dev/null 2>&1 && gamemode=true

    memory_mib=$(awk '/MemTotal:/ {printf "%d", $2 / 1024}' /proc/meminfo)
    avx=false
    grep -qm1 -w avx /proc/cpuinfo && avx=true

    if [[ "$hardware_vulkan" != true ]]; then
        verdict=unsupported
        summary=$(_ 'Not suitable for Proton/DXVK: no Vulkan GPU was found.')
    elif [[ "$vulkan_32" != true || "$umu" != true || "$gamemode" != true ]]; then
        verdict=setup-required
        summary=$(_ 'A suitable Vulkan GPU was found, but the gaming runtime is not complete yet.')
    else
        verdict=ready
        summary=$(_ 'This computer is technically ready for ECZ Gaming.')
    fi
}

print_json() {
    jq -n \
        --arg verdict "$verdict" --arg summary "$summary" --arg gpu "$gpu" \
        --arg devices "$vulkan_devices" --argjson hardwareVulkan "$hardware_vulkan" \
        --argjson softwareVulkan "$software_vulkan" --argjson vulkan32 "$vulkan_32" \
        --argjson umu "$umu" --argjson gameMode "$gamemode" \
        --argjson memoryMiB "$memory_mib" --argjson cpuAvx "$avx" \
        '{schemaVersion:1, verdict:$verdict, summary:$summary, gpu:$gpu,
          vulkan:{hardware:$hardwareVulkan, softwareOnly:$softwareVulkan, devices:$devices, driver32Bit:$vulkan32},
          runtime:{umu:$umu, gameMode:$gameMode}, system:{memoryMiB:$memoryMiB, cpuAvx:$cpuAvx}}'
}

print_human() {
    local mark_hw mark_32 mark_umu mark_gm
    mark_hw=$(_ 'no'); mark_32=$(_ 'no'); mark_umu=$(_ 'no'); mark_gm=$(_ 'no')
    [[ "$hardware_vulkan" == true ]] && mark_hw=$(_ 'yes')
    [[ "$vulkan_32" == true ]] && mark_32=$(_ 'yes')
    [[ "$umu" == true ]] && mark_umu=$(_ 'yes')
    [[ "$gamemode" == true ]] && mark_gm=$(_ 'yes')
    cat <<EOF
$(_ 'ECZ Gaming check')

$(_ 'Result'): $summary
GPU: $gpu
$(_ 'Vulkan device'): $vulkan_devices
$(_ 'Hardware Vulkan'): $mark_hw
$(_ '32-bit Vulkan driver'): $mark_32
$(_ 'UMU/Proton adapter'): $mark_umu
GameMode: $mark_gm
$(_ 'Memory'): ${memory_mib} MiB
EOF
    if (( memory_mib < 8192 )); then
        printf '%s\n' "$(_ 'Warning: less than 8 GiB RAM; modern games may use swap heavily.')"
    fi
    if [[ "$avx" != true ]]; then
        printf '%s\n' "$(_ 'Warning: this CPU has no AVX; many modern games will not start.')"
    fi
    if [[ "$software_vulkan" == true && "$hardware_vulkan" != true ]]; then
        printf '%s\n' "$(_ 'Note: llvmpipe/lavapipe is software rendering and does not count as a gaming GPU.')"
    fi
}

doctor() {
    collect_status
    if [[ ${1:-} == --json ]]; then
        print_json
    else
        print_human
    fi
}

manage() {
    exec /usr/bin/eczos-ui gaming
}

case ${1:-} in
    doctor|status)
        shift
        if (( $# > 1 )) || [[ $# -eq 1 && $1 != --json ]]; then
            usage >&2
            exit 2
        fi
        doctor "${1:-}"
        ;;
    check-ready)
        collect_status
        print_human
        [[ "$verdict" == ready ]]
        ;;
    manage)
        manage
        ;;
    runtime-info)
        jq . /usr/share/eczos/gaming/runtime-definitions/umu-launcher-1.4.0.json
        ;;
    -h|--help|help|'')
        usage
        ;;
    *)
        usage >&2
        exit 2
        ;;
esac
