#!/bin/sh

log() {
    echo "$@"
}

dt() {
    p=/proc/device-tree/"$1"
    if [ ! -e "$p" ]; then
        echo "(missing)"
    else
        cat "$p" | tr "\0" " " | sed -e 's/ $//g'; echo
    fi
}

banner() {
    cat <<EOF
# Asahi Linux System Diagnostic Dump

    Collected at:   $(date) ($(date -Iseconds))
    Username:       $(whoami)
    Hostname:       $(hostname)

EOF
}

device_info() {
    cat <<EOF
## Device information
    Model:          $(dt model)
    Compatible:     $(dt compatible)

EOF
}

firmware_versions() {
    cat <<EOF
## Firmware versions
    iBoot1:         $(dt chosen/asahi,iboot1-version)
    iBoot2:         $(dt chosen/asahi,iboot2-version)
    SFR:            $(dt chosen/asahi,system-fw-version)
    OS firmware:    $(dt chosen/asahi,os-fw-version)
    m1n1 stage 2:   $(dt chosen/asahi,m1n1-stage2-version)
    U-Boot:         $(dt chosen/u-boot,version)

EOF
}

boot_config() {
    cat <<EOF
## Boot information
    ESP UUID:       $(dt chosen/asahi,efi-system-partition)
    EFI:            $([ -e /sys/firmware/efi ] &&
                       echo available || echo unavailable)

EOF
}

system_info() {
    cat <<EOF
## System information
    Distro:         $(awk -F= '/PRETTY_NAME/ { gsub(/"/, "", $2); print $2 }' /etc/os-release)
    Kernel:         $(uname -r)
    Kernel build:   $(uname -v)
    Uptime:         $(uptime)
    Kernel cmdline: $(cat /proc/cmdline)

EOF
}


# Check pipewire profile
check_macaudio_profile() {
    local profile_config="${HOME}/.local/state/wireplumber/default-profile"
    [ -e  ${profile_config} ] \
    && sed -ne 's/^alsa_card.platform-sound=// p' ${profile_config} | grep . \
    || echo "Default"
}
macaudio_profile=$(check_macaudio_profile)

# Check for the Pro Audio profile (installed before early 2023)
check_proaudio() {
    grep "alsa_output.platform-sound.pro-output.." "${HOME}/.local/state/wireplumber/restore-stream" > /dev/null \
    && echo "yes" \
    || echo "no"
}
pro_audio=$(check_proaudio)

# Check for Configs in /etc/ (installed before mid 2023)
check_audio_oldconfs() {
    [ -e /etc/pipewire/pipewire.conf.d/*asahi* ] \
    || [ -e /etc/wireplumber/policy.lua.d/99-asahi-policy.lua ] \
    && echo "yes" \
    || echo "no"
}
old_conf=$(check_audio_oldconfs)

# Check for the racy 99-asahi* build (installed before ~Oct 2023)
check_audio_oldbuild() {
    [ -e /usr/share/wireplumber/policy.lua.d/99-asahi-policy.lua ] \
    && echo "yes" \
    || echo "no"
}
racy_build=$(check_audio_oldbuild)

# Check if snd-soc-macaudio.please_blow_up_my_speakers was requested
check_audio_macaudio() {
    grep "0" /sys/module/snd_soc_macaudio/parameters/please_blow_up_my_speakers > /dev/null \
    && echo "no" \
    || echo "yes"
}
bad_macaudio_params=$(check_audio_macaudio)

# Check that snd-soc-tas2764.apple_quirks=0x3f is being applied
check_audio_tas2764() {
    [ -e /sys/module/snd_soc_tas2764/ ] && (
        grep "63" /sys/module/snd_soc_tas2764/parameters/apple_quirks > /dev/null \
        && echo "yes" \
        || echo "no"
    ) || echo "N/A"
}
tas2764_quirks=$(check_audio_tas2764)

audio_config() {
    cat <<EOF
## Audio Configuration:
    Default profile: $macaudio_profile
    Pro Audio profile detected: $pro_audio
    Old configuration files in \`/etc/\`: $old_conf
    File conflicts in \`/usr/share/\`: $racy_build
    Speaker detonation requested: $bad_macaudio_params
    TAS2764 quirks applied: $tas2764_quirks

EOF
}

getfile() {
    cat <<EOF
## $2
\`\`\`
$(cat $1)
\`\`\`

EOF
}

cmd() {
    cat <<EOF
## $2
\`\`\`
$($1)
\`\`\`

EOF
}


package_versions() {
    echo "## Package versions"
    if [ -e /etc/arch-release ]; then
      cmd="pacman -Q"
      pkgs="m1n1 uboot-asahi asahi-scripts asahi-meta asahi-desktop-meta
            asahi-fwextract asahi-configs alsa-ucm-conf-asahi
            asahilinux-keyring linux linux-asahi linux-asahi-edge
            mesa xorg-server pipewire kwin mutter"
    elif [ -e /etc/fedora-release ]; then
      cmd="rpm -q"
      pkgs="m1n1 alsa-ucm-asahi asahi-platform-metapackage asahi-repos
            fedora-asahi-remix-scripts tiny-dfr uboot-images-armv8 kernel-16k
            kernel-16k-modules-extra asahi-fwextract dracut-asahi update-m1n1
            asahi-audio speakersafetyd wireplumber pipewire mesa"
    else
      echo "Distribution not supported"
      return
    fi
    cat <<EOF
\`\`\`
$($cmd $pkgs 2>/dev/null | sort -u)
\`\`\`

EOF
}

module_parameters() {
    echo "## Module parameters"
    for mod in asahi hid_apple hid_magicmouse; do
        [ ! -e /sys/module/$mod/parameters/ ] && continue
        echo "    $mod"
        for param in /sys/module/$mod/parameters/*; do
            echo "        $(basename "$param")=$(cat "$param" | tr -d '\0')"
        done
        echo
    done
    echo
}

logfile() {
    f="$1"
    lines="$2"
    [ -e "$1" ] || return
    echo "## Log file: \`$f\`"
    echo '```'
    if [ -z "$lines" ]; then
        cat "$f"
    else
        tail -n "$lines" "$f"
    fi
    echo '```'
    echo
}

environment() {
    echo "## Environment"
    set | grep -E 'MESA|AGX|ASAHI|XDG_SESSION_TYPE|DISPLAY|TERM|LANG|LOCALE|LC_' | sed 's/^/    /'
    echo
}

diagnose() {
    f="$1"

    >$f

    log "Collecting system diagnostic information..."
    log

    (
        exec >"$f" 2>&1
        banner
        device_info
        firmware_versions
        boot_config
        system_info
        audio_config
        environment
        getfile /proc/mounts "Mounts"
        package_versions
        cmd lsblk "Block devices"
        cmd lspci "PCI devices"
        getfile /proc/bus/input/devices "Input devices"
        cmd lsmod "Loaded modules"
        module_parameters
        cmd 'journalctl -b 0 -tkernel' "Kernel log"
        cmd 'journalctl -b -1 -tkernel' "Kernel log (last boot)"
        logfile /var/log/Xorg.0.log
        logfile /var/log/pacman.log 500
    )

    log "Saved diagnostic information to $f"

    if [ "$macaudio_profile" != "HiFi" -a "$macaudio_profile" != "Default" ]; then
        echo
        echo "Pipewire macaudio profile is \"${macaudio_profile}\"."
        echo "Headphones and speakers will not work. Select the \"Default\" or \"HiFi\" profile."
    fi

    if [ "$pro_audio" = "yes" ] || \
       [ "$old_conf" = "yes" ] || \
       [ "$racy_build" = "yes" ] || \
       [ "$bad_macaudio_params" = "yes" ] || \
       [ "$tas2764_quirks" = "no" ]; then
        echo
        echo "!! IMPORTANT !!"
        echo "Your audio configuration is in an invalid state. It is likely that you tried to"
        echo "enable speakers early, despite numerous and very explicit warnings not to do so."
        echo "Potential reason(s) you are seeing this message: "
        (
            [ "$pro_audio" = "yes" ] && echo "    - The Pro Audio profile is/was enabled for the internal speakers."
            [ "$old_conf" = "yes" ] && echo "    - You have files in /etc/ from a prerelease version of asahi-audio."
            [ "$racy_build" = "yes" ] && echo "    - You have files in /usr/share/ from a prerelease version of asahi-audio."
            [ "$bad_macaudio_params" = "yes" ] && echo "    - You have tried to manually circumvent our kernel-level safety controls."
            [ "$tas2764_quirks" = "no" ] && echo "    - Required speaker codec settings are not being applied."
        )
        echo "Please go to https://asahilinux.org/docs/sw/undoing-early-speaker-hacks/ for fixes."
        echo "Do NOT file audio-related bugs until you have tried ALL fixes suggested at the page above."
        echo "Your bugs will be ignored and you will not be assisted."
    fi


    plat="$(cat /proc/device-tree/compatible | sed -re 's/.*apple,(t....).*/\1/g')"
    ver="$(tr -d '\0' </proc/device-tree/chosen/asahi,os-fw-version)"
    case "${plat}:${ver}" in
        t8103:12.3*) ;;
        t600[012]:12.3*) ;;
        t8112:12.4*) ;;

        t8103:13.5*) ;;
        t600[012]:13.5*) ;;
        t8112:13.5*) ;;
        t602[012]:13.5*) ;;
        *)
            echo
            echo "** WARNING! **"
            echo "You are using an unsupported firmware version ($ver) on this platform ($plat)."
            echo "This means you explicitly chose expert mode when installing Asahi Linux,"
            echo "and then explicitly selected a non-default unsupported version."
            echo "You are on your own. Please do not file bugs. We can't help you."
            echo "Reinstall without using expert mode if you want support."
            ;;
    esac

    if [ -e /etc/fedora-release ]; then
        if uname -r | grep -qv '+16k$'; then
            echo
            echo "** WARNING! **"
            echo "Your system is not running a 16k page kernel. This is unsupported and will not"
            echo "work properly; see https://discussion.fedoraproject.org/t/87711 for how to fix."
        elif [ ! -e /etc/sysconfig/kernel ]; then
            echo
            echo "** WARNING! **"
            echo "/etc/sysconfig/kernel is missing, kernel updates may not install properly"
            echo "See https://discussion.fedoraproject.org/t/87711/3 for how to fix."
        elif grep -q DEFAULTKERNEL=kernel-core /etc/sysconfig/kernel; then
            echo
            echo "** WARNING! **"
            echo "/etc/sysconfig/kernel is setting a 4k kernel as default; this is unsupported"
            echo "and will not work properly; see https://discussion.fedoraproject.org/t/87711"
            echo "for how to fix."
        fi

        if ! rpm -q asahi-platform-metapackage > /dev/null 2>&1; then
            echo
            echo "** WARNING! **"
            echo "The asahi-platform-metapackage package is not installed, you may be missing"
            echo "required platform dependencies. See https://discussion.fedoraproject.org/t/95301"
            echo "for how to fix it."
        fi
    fi
}

if [ -z "$1" ]; then
    diagnose "$HOME/asahi-diagnose-$(date +%Y%m%d-%H%M%S).txt"
elif [ "$1" = "-" ]; then
    diagnose /dev/stdout
else
    diagnose "$1"
fi
