#!/bin/bash
# Is this machine the classroom?
#
# One list of properties, run against whatever the lab is currently
# holding. A fresh install and a machine upgraded from the old sway or
# Hyprland shell have to answer it identically — that is the whole point
# of the migration work, and the reason this is a file rather than a
# paragraph in a report.
#
#   tools/lab/converged-check            the properties
#   tools/lab/converged-check --restart  and again after a session restart
#
# Every check reads the running machine. Nothing here consults the
# repository, so a check cannot pass by agreeing with the source it came
# from.
set -uo pipefail

ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
LAB="$ROOT/tools/lab/lab"
NAME="${LAB_NAME:-classroom-v2-lab}"

PASS=0
FAIL=0

in_lab() { docker exec "$NAME" bash -c "$1" 2>/dev/null; }

# As the session itself reads configuration: the cascade of the running
# shell, not one this script made up.
session_config() {
    local dirs
    dirs=$(in_lab 'p=$(pgrep -x plasmashell | head -1); tr "\0" "\n" < /proc/$p/environ | grep "^XDG_CONFIG_DIRS=" | cut -d= -f2-')
    docker exec -u classroom -e XDG_RUNTIME_DIR=/run/user/1000 -e HOME=/home/classroom \
        -e LANG=C.UTF-8 -e "XDG_CONFIG_DIRS=$dirs" "$NAME" \
        kreadconfig6 "$@" 2>/dev/null | tr -d '\r'
}

running() { in_lab "pgrep -x $1 | wc -l"; }

# Which process is actually answering org.freedesktop.Notifications. On a
# machine that still has mako installed this is the question that matters:
# the name is taken by whoever gets there first.
notification_owner() {
    local pid
    pid=$(in_lab 'XDG_RUNTIME_DIR=/run/user/1000 runuser -u classroom -- \
        busctl --user --no-pager call org.freedesktop.DBus /org/freedesktop/DBus \
        org.freedesktop.DBus GetConnectionUnixProcessID s org.freedesktop.Notifications' \
        | awk '{print $2}')
    [[ -n "$pid" ]] && in_lab "cat /proc/$pid/comm"
}

# logind answers for the running configuration, not for a file on disk.
logind_property() {
    in_lab "busctl get-property org.freedesktop.login1 /org/freedesktop/login1 \
        org.freedesktop.login1.Manager $1" | cut -d'"' -f2
}

APPLETS=/home/classroom/.config/plasma-org.kde.plasma.desktop-appletsrc

check() {
    # check DESCRIPTION EXPECTED ACTUAL
    if [[ "$2" == "$3" ]]; then
        printf '  \033[32mPASS\033[0m  %-52s %s\n' "$1" "$3"
        PASS=$((PASS + 1))
    else
        printf '  \033[31mFAIL\033[0m  %-52s got [%s] want [%s]\n' "$1" "$3" "$2"
        FAIL=$((FAIL + 1))
    fi
}

section() { printf '\n%s\n' "$1"; }

run_checks() {
section "the session"
check "kwin_wayland running" 1 "$(running kwin_wayland)"
check "plasmashell running" 1 "$(running plasmashell)"

section "the old shell is gone"
check "waybar not running" 0 "$(running waybar)"
check "mako not running" 0 "$(running mako)"
# The bracket keeps the pattern from matching the command that carries it.
check "classroom dock not running" 0 "$(in_lab 'pgrep -f "[c]lassroom-dock" | wc -l')"
# The lab's own outer compositor is sway, so the question is whether any
# sway is running that is not the harness's.
check "no sway but the lab harness's" 0 \
    "$(in_lab 'pgrep -x sway | while read -r p; do tr "\0" " " < /proc/$p/cmdline | grep -q outer-sway.conf || echo x; done | grep -c x || true')"
check "Hyprland not running" 0 "$(running Hyprland)"
check "waybar activation removed" 0 \
    "$(in_lab 'find /etc/systemd/user /etc/xdg/systemd/user /home/classroom/.config/systemd/user -name "waybar.service" -path "*.wants/*" 2>/dev/null | wc -l')"
check "mako activation removed" 0 \
    "$(in_lab 'find /etc/systemd/user /etc/xdg/systemd/user /home/classroom/.config/systemd/user -name "mako.service" -path "*.wants/*" 2>/dev/null | wc -l')"
check "waybar masked" masked "$(in_lab 'XDG_RUNTIME_DIR=/run/user/1000 runuser -u classroom -- systemctl --user is-enabled waybar.service || true')"
check "mako masked" masked "$(in_lab 'XDG_RUNTIME_DIR=/run/user/1000 runuser -u classroom -- systemctl --user is-enabled mako.service || true')"
check "no login shell starting a compositor" 0 \
    "$(in_lab 'grep -lE "exec (sway|Hyprland|start-hyprland|classroom-session)" /home/classroom/.bash_profile 2>/dev/null | wc -l')"
check "no tty1 autologin drop-in" 0 \
    "$(in_lab 'ls /etc/systemd/system/getty@tty1.service.d/autologin.conf 2>/dev/null | wc -l')"
check "no autostart entry for the old shell" 0 \
    "$(in_lab 'grep -lE "^Exec=.*(waybar|mako|classroom-dock)" /home/classroom/.config/autostart/*.desktop 2>/dev/null | wc -l')"

section "device.conf"
check "COMPOSITOR removed" 0 "$(in_lab 'grep -c "^COMPOSITOR=" /etc/ekklesia-classroom/device.conf || true')"
check "not on the hyprland channel" 0 "$(in_lab 'grep -c "^CHANNEL=hyprland" /etc/ekklesia-classroom/device.conf || true')"

section "the configuration cascade"
check "classroom settings in the session's cascade" 1 \
    "$(in_lab 'p=$(pgrep -x plasmashell | head -1); tr "\0" "\n" < /proc/$p/environ | grep -c "^XDG_CONFIG_DIRS=.*ekklesia-classroom/xdg"')"
check "look and feel authoritative" org.ekklesia.classroom.desktop \
    "$(session_config --file kdeglobals --group KDE --key LookAndFeelPackage)"
check "and immutable" 1 \
    "$(in_lab 'grep -c "^LookAndFeelPackage\[\$i\]=" /etc/ekklesia-classroom/xdg/kdeglobals')"
check "the palette is the packaged one" 20,28,32 \
    "$(session_config --file kdeglobals --group 'Colors:Window' --key BackgroundNormal)"

section "the panel"
check "applet count" 10 "$(in_lab "grep -c '^plugin=' $APPLETS")"
check "Parent Call launcher" 1 \
    "$(in_lab "grep -c 'ekklesia-parent-call.desktop' $APPLETS")"
check "quick launch, one widget" 1 \
    "$(in_lab "grep -c '^plugin=org.kde.plasma.quicklaunch' $APPLETS")"
check "the applications are the room's" 1 \
    "$(in_lab "grep -c 'launchers=applications:ekklesia-wonderink.desktop,applications:google-chrome.desktop' $APPLETS")"
check "network, volume, notifications, clock" 4 \
    "$(in_lab "grep -cE '^plugin=org.kde.plasma.(networkmanagement|volume|notifications|digitalclock)$' $APPLETS")"
check "no kickoff" 0 "$(in_lab "grep -c 'plugin=org.kde.plasma.kickoff' $APPLETS")"
check "no pager" 0 "$(in_lab "grep -c 'plugin=org.kde.plasma.pager' $APPLETS")"
check "no system tray" 0 "$(in_lab "grep -c 'systemtray' $APPLETS")"
check "no discover or system settings" 0 \
    "$(in_lab "grep -cE 'discover.desktop|systemsettings.desktop' $APPLETS")"
check "the packaged wallpaper" 1 \
    "$(in_lab "grep -c 'Image=file:///usr/share/backgrounds/ekklesia/classroom-calm.png' $APPLETS")"

section "it will not strand a teacher"
check "no automatic lock" false "$(session_config --file kscreenlockerrc --group Daemon --key Autolock)"
check "no lock on resume" false "$(session_config --file kscreenlockerrc --group Daemon --key LockOnResume)"
check "the lock action is forbidden" false \
    "$(session_config --file kdeglobals --group 'KDE Action Restrictions' --key action/lock_screen)"
check "power button does nothing" 0 \
    "$(session_config --file powermanagementprofilesrc --group AC --group HandleButtonEvents --key powerButtonAction)"
check "no idle suspend, dim or blank configured" 0 \
    "$(in_lab 'grep -cE "^\[(AC|Battery|LowBattery)\]\[(SuspendSession|DimDisplay|DPMSControl)\]" /etc/ekklesia-classroom/xdg/powermanagementprofilesrc || true')"
check "and the profiles are immutable" 3 \
    "$(in_lab 'grep -cE "^\[(AC|Battery|LowBattery)\]\[\\\$i\]" /etc/ekklesia-classroom/xdg/powermanagementprofilesrc || true')"
check "logind ignores the power key" ignore "$(logind_property HandlePowerKey)"
check "logind ignores a long press" ignore "$(logind_property HandlePowerKeyLongPress)"
check "logind has no idle action" ignore "$(logind_property IdleAction)"
check "logind ignores the lid" ignore "$(logind_property HandleLidSwitch)"

section "lockdown still in force"
for key in run_command shell_access logout; do
    check "$key" false "$(session_config --file kdeglobals --group 'KDE Action Restrictions' --key "$key")"
done
check "the panel cannot be edited" false \
    "$(session_config --file kdeglobals --group 'KDE Action Restrictions' --key plasma/plasmashell/unlockedDesktop)"

section "autologin"
check "sddm enabled" enabled "$(in_lab 'systemctl is-enabled sddm.service || true')"
# Not a reading of the configuration: what SDDM actually did at the last
# boot of this machine. It authenticates the classroom through PAM and
# launches the session; the lab has no display hardware for the session to
# land on, so everything past this point is a hardware test.
check "sddm autologged the classroom in at boot" yes \
    "$(in_lab 'journalctl -u sddm --no-pager 2>/dev/null | grep -q "Authentication for user  .classroom.  successful" && echo yes || echo no')"
check "and chose the Plasma session" yes \
    "$(in_lab 'journalctl -u sddm --no-pager 2>/dev/null | grep -q "wayland-sessions/plasma.desktop. selected" && echo yes || echo no')"
check "autologin user" classroom \
    "$(in_lab 'grep -A3 "^\[Autologin\]" /etc/sddm.conf.d/ekklesia-classroom.conf | sed -n "s/^User=//p"')"
check "autologin session" plasma \
    "$(in_lab 'grep -A3 "^\[Autologin\]" /etc/sddm.conf.d/ekklesia-classroom.conf | sed -n "s/^Session=//p"')"
check "the session it names exists" 1 \
    "$(in_lab 'ls /usr/share/wayland-sessions/plasma.desktop 2>/dev/null | wc -l')"
check "the classroom uid is inside the greeter's range" 1 \
    "$(in_lab 'uid=$(id -u classroom); min=$(sed -n "s/^MinimumUid=//p" /etc/sddm.conf.d/ekklesia-classroom.conf); max=$(sed -n "s/^MaximumUid=//p" /etc/sddm.conf.d/ekklesia-classroom.conf); [ "$uid" -ge "$min" ] && [ "$uid" -le "$max" ] && echo 1 || echo 0')"

section "notifications belong to Plasma"
check "the old daemon cannot be activated" 1 \
    "$(in_lab 'grep -c "^Exec=/bin/false" /usr/local/share/dbus-1/services/fr.emersion.mako.service 2>/dev/null || true')"
check "and Plasma owns the notification service" plasmashell "$(notification_owner)"

section "the room's own parts survived"
check "parent call installed" 1 "$(in_lab 'ls /usr/local/bin/classroom-parent-call 2>/dev/null | wc -l')"
check "parent call icon installed" 1 \
    "$(in_lab 'ls /usr/share/icons/hicolor/scalable/apps/ekklesia-parent-call.svg 2>/dev/null | wc -l')"
check "wonderink installed" 1 "$(in_lab 'ls /usr/local/bin/classroom-wonderink 2>/dev/null | wc -l')"
check "the maintenance chord is registered" 1 \
    "$(in_lab 'grep -c "^X-KDE-Shortcuts=Meta+Ctrl+Alt+Shift+K" /usr/share/applications/ekklesia-admin-terminal.desktop || true')"
check "no sudo rule for the classroom" 0 \
    "$(in_lab 'grep -rl classroom /etc/sudoers /etc/sudoers.d 2>/dev/null | wc -l')"
check "the panel is supervised" always \
    "$(in_lab 'XDG_RUNTIME_DIR=/run/user/1000 runuser -u classroom -- systemctl --user show plasma-plasmashell.service -p Restart --value')"
check "audio policy active" active \
    "$(in_lab 'XDG_RUNTIME_DIR=/run/user/1000 runuser -u classroom -- systemctl --user is-active ekklesia-classroom-audio.service || true')"
}

run_checks

if [[ "${1:-}" == "--restart" ]]; then
    section "and again after logging out and back in"
    "$LAB" plasma-down >/dev/null
    "$LAB" plasma-up >/dev/null
    sleep 3
    run_checks
fi

printf '\n%s passed, %s failed\n' "$PASS" "$FAIL"
[[ "$FAIL" -eq 0 ]]
