#!/usr/bin/env bash

# Right-click a file and do something useful with it.
#
# macOS has a Share sheet and Quick Actions in Finder; Windows has "Send to".
# Both are among the few context-menu entries people genuinely reach for, and
# a stock Linux file manager has neither.
#
# What must hold:
#
#   1. The transcoder never writes over its input, and never over an earlier
#      output. Somebody right-clicking a video to shrink it must not lose the
#      original, and running it twice must not eat the first result.
#   2. It refuses what it cannot do rather than handing ffmpeg a guess.
#   3. The extensions only offer themselves for files they can act on, decided
#      by mime type rather than extension, and only for a real local file.
#   4. Sending a file reuses panama-kdeconnect rather than inventing a second
#      way to talk to a phone.
#   5. The menu entry for sending is absent when no phone is reachable. An
#      entry that is present and fails is worse than one that is absent,
#      because the absence explains itself.

set -uo pipefail

repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
extensions="$repo_dir/config/local/share/nautilus-python/extensions"
share="$extensions/panama-share.py"
transcode_ext="$extensions/panama-transcode.py"
transcode="$repo_dir/bin/panama-transcode"
linker="$repo_dir/setup/scripts/link-dotfiles"
packages="$repo_dir/setup/packages/desktop-packages"

findings=()
note() { findings+=("$1"); }

for file in "$share" "$transcode_ext"; do
    [[ -r "$file" ]] || note "$(basename "$file") is missing"
done
[[ -x "$transcode" ]] || { printf 'nautilus contract: %s is not executable\n' "$transcode" >&2; exit 1; }

# Both extensions must be importable Python, or Nautilus loads nothing and
# says nothing about why.
for file in "$share" "$transcode_ext"; do
    [[ -r "$file" ]] || continue
    python3 -c "import ast,sys; ast.parse(open(sys.argv[1]).read())" "$file" 2>/dev/null \
        || note "$(basename "$file") is not valid Python, so Nautilus would silently load nothing"
    grep -q 'Nautilus.MenuProvider' "$file" \
        || note "$(basename "$file") does not implement MenuProvider, so it would never appear in a menu"
done

# ── 1 & 2. The transcoder protects the input and earlier outputs ────────────

work="$(mktemp -d)"
trap 'rm -rf "$work"' EXIT

if command -v ffmpeg >/dev/null 2>&1; then
    ffmpeg -nostdin -loglevel error -f lavfi -i testsrc=duration=1:size=640x480:rate=10 \
        -pix_fmt yuv420p "$work/clip.mp4" -y 2>/dev/null

    before="$(sha256sum "$work/clip.mp4" | cut -d' ' -f1)"
    "$transcode" video "$work/clip.mp4" 480p >/dev/null 2>&1 \
        || note 'transcoding a real video failed'
    after="$(sha256sum "$work/clip.mp4" | cut -d' ' -f1)"
    [[ "$before" == "$after" ]] || note 'the transcoder modified its own input'
    [[ -f "$work/clip-480p.mp4" ]] || note 'the transcoder wrote no output beside the input'

    first="$(sha256sum "$work/clip-480p.mp4" | cut -d' ' -f1)"
    "$transcode" video "$work/clip.mp4" 480p >/dev/null 2>&1
    [[ "$(sha256sum "$work/clip-480p.mp4" | cut -d' ' -f1)" == "$first" ]] \
        || note 'running the transcoder twice overwrote the first output'
    [[ -f "$work/clip-480p-2.mp4" ]] \
        || note 'a second run did not write a numbered output, so one of the two was lost'
else
    note 'ffmpeg is not installed, so the transcoder could not be exercised'
fi

# An unknown size or format is refused before ffmpeg is handed anything.
"$transcode" video "$work/clip.mp4" 9000p >/dev/null 2>&1 \
    && note 'an unknown video size was accepted'
"$transcode" image "$work/clip.mp4" bmp >/dev/null 2>&1 \
    && note 'an unknown image format was accepted'
"$transcode" video "$work/does-not-exist.mp4" 480p >/dev/null 2>&1 \
    && note 'a file that does not exist was accepted'

# ── 3. Only files they can act on ───────────────────────────────────────────

grep -q 'get_mime_type' "$transcode_ext" \
    || note 'the transcode menu decides by extension rather than mime type, so a mislabelled file gets an entry it fails on'
for file in "$share" "$transcode_ext"; do
    [[ -r "$file" ]] || continue
    grep -q "parsed.scheme != \"file\"" "$file" \
        || note "$(basename "$file") does not check that the file is local, so it would offer to act on a remote URI"
    grep -q 'len(files) != 1' "$file" \
        || note "$(basename "$file") acts on a multiple selection, which would start one job per file from a single click"
done

# ── 4 & 5. Sending reuses the phone helper, and hides without a phone ───────

grep -q 'panama-kdeconnect' "$share" \
    || note 'the share extension does not use the existing phone helper'
grep -q 'send-file' "$share" \
    || note 'the share extension does not use the helper verb that sends a file'
grep -q 'reachable' "$share" \
    || note 'the share entry appears whether or not a phone is reachable, so it would be present and fail'

# ── Installed where Nautilus looks ──────────────────────────────────────────

grep -q 'nautilus-python/extensions' "$linker" \
    || note 'link-dotfiles does not publish the extensions, so Nautilus would never see them'
grep -qx 'nautilus-python' "$packages" \
    || note 'nautilus-python is not declared, so the extensions would not load on a fresh machine'
(( $(grep -cx 'nautilus-python' "$packages") == 1 )) \
    || note 'nautilus-python is declared more than once'

if (( ${#findings[@]} > 0 )); then
    printf 'nautilus extensions contract: %d finding(s)\n' "${#findings[@]}" >&2
    printf '  - %s\n' "${findings[@]}" >&2
    exit 1
fi

printf 'nautilus extensions contract: PASS\n'
