#!/usr/bin/env bash

# Storage has to be honest about three things, and each of them is a way the
# page could quietly lie:
#
#   1. btrfs subvolumes mounted at / and /home are ONE filesystem sharing one
#      pool of free space. df reports them as two, and a page that copies df
#      shows the user twice the free space they have.
#   2. zram is a block device and is not storage. Counting it as a drive
#      overstates how much disk this machine has by 8 GB.
#   3. unmount and eject must refuse anything that is not removable. The UI is
#      the thing asking, and a UI can be wrong.
#
# The expensive folder scan is NOT exercised here: measuring a terabyte-scale
# library is not something a test should do on the machine someone is using.

set -uo pipefail

repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
helper="$repo_dir/config/dot/quickshell/scripts/panama-disks"
service="$repo_dir/config/dot/quickshell/services/Disks.qml"
page="$repo_dir/config/dot/quickshell/modules/settings/StoragePage.qml"

fail() {
    printf 'disks contract: %s\n' "$1" >&2
    exit 1
}

[[ -x "$helper" ]] || fail 'panama-disks is missing or not executable'
[[ -r "$service" ]] || fail 'the Disks service is missing'
[[ -r "$page" ]] || fail 'StoragePage is missing'

# ── The service reports failure rather than inventing data ───────────────────
grep -q 'pragma Singleton' "$service" || fail 'Disks is not a singleton'
grep -q 'property string lastError' "$service" || fail 'Disks cannot report a failure'
grep -q 'function refresh(): void' "$service" || fail 'Disks has no refresh'
grep -q 'function scan(): void' "$service" || fail 'Disks has no folder scan'
grep -qE 'command\s*:\s*"' "$service" && fail 'Process command must be an argument array'

# The expensive read must not run on open; that is the entire reason it is a
# separate command.
grep -q 'Component.onCompleted: Disks.refresh()' "$page" \
    || fail 'the page does not read the cheap snapshot when it opens'
grep -q 'Component.onCompleted: Disks.scan()' "$page" \
    && fail 'the page starts the expensive folder walk on open'

# Partitioning stays out, deliberately and visibly.
grep -qiE 'mkfs|sfdisk|parted|wipefs|dd if=' "$helper" \
    && fail 'the helper can partition or format, which this page deliberately does not do'

# ── Snapshot shape ───────────────────────────────────────────────────────────
snapshot="$("$helper" snapshot)" || fail 'snapshot failed'
command -v jq >/dev/null 2>&1 || { printf 'disks contract: SKIP (no jq)\n'; exit 0; }

jq -e '(.drives | type == "array") and (.filesystems | type == "array") and (.swap | type == "array")' \
    <<<"$snapshot" >/dev/null || fail 'snapshot is missing one of drives, filesystems, or swap'

# zram is swap, never a drive.
jq -e '[.drives[].name | startswith("zram")] | any | not' <<<"$snapshot" >/dev/null \
    || fail 'zram is reported as a drive, which overstates how much disk this machine has'
jq -e '[.swap[].kind] | index("zram") != null or (. | length == 0)' <<<"$snapshot" >/dev/null \
    || fail 'zram is not reported as swap'

# One entry per DEVICE, not per mount point. Two entries for one device would
# be the doubled-free-space bug.
duplicates="$(jq -r '[.filesystems[].device] | group_by(.) | map(select(length > 1)) | flatten | join(", ")' <<<"$snapshot")"
[[ -z "$duplicates" ]] \
    || fail "these devices appear more than once, so their free space is counted twice: $duplicates"

# Every filesystem has to carry the numbers the page draws.
jq -e '[.filesystems[] | (.sizeBytes > 0) and (.mountpoints | length > 0)] | all' <<<"$snapshot" >/dev/null \
    || fail 'a filesystem is missing its size or its mount points'

# A shared filesystem lists "/" first, because that is what it is called.
jq -e '[.filesystems[] | select(.mountpoints | index("/")) | .mountpoints[0] == "/"] | all' \
    <<<"$snapshot" >/dev/null || fail 'the root filesystem does not lead with "/"'

# ── Refusals, against a recorded tree ────────────────────────────────────────
# Never against real hardware. An earlier version of this test ran unmount on
# whatever device happened to hold the root filesystem and passed only because
# the kernel refused -- which tests the kernel, not the helper, and would have
# unmounted /home the moment nothing held it open.
work="$(mktemp -d /tmp/panama-disks.XXXXXX)"
trap 'rm -rf "$work"' EXIT

cat >"$work/tree.json" <<'FIXTURE'
{"blockdevices":[
  {"name":"nvme0n1","path":"/dev/nvme0n1","size":2000398934016,"type":"disk","fstype":null,
   "mountpoints":[],"model":"Fixed Disk","serial":"FIXED1","rm":false,"hotplug":false,"rota":false,
   "fssize":null,"fsused":null,"fsavail":null,
   "children":[{"name":"nvme0n1p1","path":"/dev/nvme0n1p1","size":2000398934016,"type":"part",
     "fstype":"btrfs","mountpoints":["/"],"model":null,"serial":null,"rm":false,"hotplug":false,
     "rota":false,"fssize":2000398934016,"fsused":1000000000000,"fsavail":1000398934016}]},
  {"name":"sdb","path":"/dev/sdb","size":32000000000,"type":"disk","fstype":null,
   "mountpoints":[],"model":"USB Stick","serial":"USB1","rm":true,"hotplug":true,"rota":false,
   "fssize":null,"fsused":null,"fsavail":null,
   "children":[{"name":"sdb1","path":"/dev/sdb1","size":32000000000,"type":"part",
     "fstype":"vfat","mountpoints":["/run/media/user/USB"],"model":null,"serial":null,
     "rm":true,"hotplug":true,"rota":false,"fssize":32000000000,"fsused":1000000000,
     "fsavail":31000000000}]}
]}
FIXTURE

# A fake udisksctl, so a refusal that should never reach the system is visible
# as an empty log rather than inferred from an exit code.
mkdir -p "$work/bin"
cat >"$work/bin/udisksctl" <<'STUB'
#!/usr/bin/env bash
printf '%s\n' "$*" >>"$PANAMA_DISKS_CALL_LOG"
STUB
chmod +x "$work/bin/udisksctl"

export PANAMA_DISKS_LSBLK="$work/tree.json"
export PANAMA_DISKS_CALL_LOG="$work/calls"
export PATH="$work/bin:$PATH"
: >"$PANAMA_DISKS_CALL_LOG"

# The root filesystem is not removable, and no argument may make it so.
"$helper" unmount /dev/nvme0n1p1 >/dev/null 2>&1 \
    && fail 'unmount accepted the root filesystem'
"$helper" eject /dev/nvme0n1 >/dev/null 2>&1 \
    && fail 'eject accepted a fixed drive'
[[ ! -s "$PANAMA_DISKS_CALL_LOG" ]] \
    || fail "a refused device still reached udisksctl: $(cat "$PANAMA_DISKS_CALL_LOG")"

"$helper" unmount 'not-a-device' >/dev/null 2>&1 \
    && fail 'unmount accepted something that is not a device path'
"$helper" unmount '/dev/../etc/passwd' >/dev/null 2>&1 \
    && fail 'unmount accepted a path escaping /dev'
"$helper" unmount '/dev/sdb99' >/dev/null 2>&1 \
    && fail 'unmount accepted a device that does not exist'
[[ ! -s "$PANAMA_DISKS_CALL_LOG" ]] \
    || fail "a rejected path still reached udisksctl: $(cat "$PANAMA_DISKS_CALL_LOG")"

# The removable one is allowed, and reaches udisksctl with separate arguments.
"$helper" unmount /dev/sdb1 >/dev/null 2>&1 \
    || fail 'unmount refused a removable partition'
grep -Fxq 'unmount -b /dev/sdb1' "$PANAMA_DISKS_CALL_LOG" \
    || fail "unmount did not reach udisksctl correctly: $(cat "$PANAMA_DISKS_CALL_LOG")"

"$helper" bogus-command >/dev/null 2>&1 \
    && fail 'an unknown command was accepted'

unset PANAMA_DISKS_LSBLK PANAMA_DISKS_CALL_LOG

printf 'disks contract: PASS (%d drives, %d filesystems)\n' \
    "$(jq '.drives | length' <<<"$snapshot")" \
    "$(jq '.filesystems | length' <<<"$snapshot")"
