#!/usr/bin/env bash

# Every GTK theme name Panama sets must be a theme that is actually installed.
#
# This exists because of a bug that was invisible for weeks. ColorScheme set
# gtk-theme to "Adwaita-dark" for dark and "Adwaita" for light. Neither is
# installed on Fedora 44 -- only adw-gtk3 and adw-gtk3-dark are -- and GTK
# responds to an unknown theme name by silently falling back to its built-in
# default, which is LIGHT.
#
# So light mode appeared to work, dark mode produced light windows, and nothing
# anywhere reported an error. Applications that take their cue from the GTK
# theme rather than the portal -- Chromium and Electron among them -- were stuck
# light with no way to diagnose it from inside the application.
#
# The failure is silent by construction, so it needs a test rather than a
# comment. Checks the compositor-facing setting and the generated GTK config
# agree, and that both name something real.
#
# It also covers the second half of GTK theming: settings.ini names a theme,
# gtk.css overrides that theme's colours. Those colours used to be baked in --
# #82aaff written out by hand, and the GTK4 "light" gtk.css a byte-for-byte
# copy of the dark one, so a light desktop drew dark GTK4 windows. They are now
# a marked block that panama-theme-apps rewrites from the active theme, with a
# thousand lines of vendored structural CSS around it that must survive
# untouched.

set -uo pipefail

repo_dir="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
color_scheme="$repo_dir/config/dot/quickshell/services/ColorScheme.qml"
theme_apps="$repo_dir/config/dot/quickshell/scripts/panama-theme-apps"

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

theme_installed() {
    local name="$1" dir
    for dir in /usr/share/themes "$HOME/.themes" "$HOME/.local/share/themes"; do
        [[ -d "$dir/$name/gtk-3.0" ]] && return 0
    done
    return 1
}

# ── The names ColorScheme sets must exist ────────────────────────────────────
names="$(grep -oE 'root\.dark \? "[a-zA-Z0-9-]+" : "[a-zA-Z0-9-]+"' "$color_scheme" \
    | grep -oE '"[a-zA-Z0-9-]+"' | tr -d '"' | grep -E '^adw-|^Adwaita' | sort -u)"
[[ -n "$names" ]] || fail 'could not find the GTK theme names in ColorScheme.qml -- this contract is not reading it correctly'

while read -r name; do
    [[ -n "$name" ]] || continue
    theme_installed "$name" \
        || fail "ColorScheme sets gtk-theme to \"$name\", which is not installed. GTK falls back to its light default when a theme is missing, so this produces light windows in dark mode with no error anywhere."
done <<<"$names"

# ── The generated GTK config must agree, in both directions ──────────────────
# Generated into a fixture rather than the live config, so running this cannot
# retheme the desktop it is running on.
fixture="$(mktemp -d /tmp/panama-gtk-theme.XXXXXX)"
trap 'rm -rf "$fixture"' EXIT

for version in 3.0 4.0; do
    mkdir -p "$fixture/gtk-$version"
    cp "$repo_dir/config/dot/gtk-$version/settings.ini.template" "$fixture/gtk-$version/" \
        || fail "gtk-$version has no settings.ini.template -- the generated file would never be produced"
done

for scheme in dark light; do
    XDG_CONFIG_HOME="$fixture" "$theme_apps" "$scheme" >/dev/null 2>&1

    for version in 3.0 4.0; do
        generated="$fixture/gtk-$version/settings.ini"
        [[ -r "$generated" ]] || fail "gtk-$version settings.ini was not generated for $scheme"

        grep -q '@GTK_THEME@\|@PREFER_DARK@' "$generated" \
            && fail "gtk-$version settings.ini still contains an unsubstituted placeholder for $scheme"

        theme="$(sed -n 's/^gtk-theme-name=//p' "$generated")"
        prefer="$(sed -n 's/^gtk-application-prefer-dark-theme=//p' "$generated")"

        theme_installed "$theme" \
            || fail "gtk-$version settings.ini names \"$theme\" for $scheme, which is not installed"

        if [[ "$scheme" == "dark" ]]; then
            [[ "$prefer" == "1" ]] || fail "gtk-$version asks for prefer-dark=$prefer in dark mode"
            [[ "$theme" == *dark* ]] || fail "gtk-$version uses \"$theme\" in dark mode, which is not a dark theme"
        else
            [[ "$prefer" == "0" ]] || fail "gtk-$version asks for prefer-dark=$prefer in light mode"
            [[ "$theme" != *dark* ]] || fail "gtk-$version uses \"$theme\" in light mode, which is a dark theme"
        fi
    done
done

# ── The generated colour block ───────────────────────────────────────────────
catalog="$repo_dir/config/dot/quickshell/config/themes.json"
gtk_css_files=(gtk-3.0/gtk.css gtk-4.0/gtk.css gtk-4.0/gtk-dark.css)

for relative in "${gtk_css_files[@]}"; do
    tracked="$repo_dir/config/dot/$relative"
    [[ -r "$tracked" ]] || fail "$relative is missing"

    grep -q 'PANAMA THEME BEGIN' "$tracked" \
        || fail "$relative has no PANAMA THEME BEGIN marker, so the palette is never written into it and GTK keeps whatever colours the file shipped with"
    grep -q 'PANAMA THEME END' "$tracked" \
        || fail "$relative has no PANAMA THEME END marker; the generator would rewrite the rest of the file"

    # The shipped file has to be valid before it has ever been regenerated: a
    # fresh checkout renders GTK windows before the first theme change.
    grep -q '@define-color window_bg_color' "$tracked" \
        || fail "$relative ships without a window_bg_color, so a fresh checkout draws GTK windows in adw-gtk3's stock greys"

    cp "$tracked" "$fixture/$relative"
done

mkdir -p "$fixture/panama"

# One dark theme and one light one, named through settings.json the way the
# shell names them.
for pair in "dark:$(jq -r .defaultDark "$catalog")" "light:$(jq -r .defaultLight "$catalog")"; do
    scheme="${pair%%:*}"
    theme_id="${pair#*:}"
    want_bg="$(jq -r --arg id "$theme_id" '.themes[] | select(.id == $id) | .palette.bg' "$catalog")"
    want_accent="$(jq -r --arg id "$theme_id" '.themes[] | select(.id == $id) | .accent' "$catalog")"

    jq -n --arg id "$theme_id" --arg scheme "$scheme" \
        '{colorScheme: $scheme, themeProfileId: $id}' >"$fixture/panama/settings.json"
    XDG_CONFIG_HOME="$fixture" "$theme_apps" "$scheme" >/dev/null 2>&1

    for relative in "${gtk_css_files[@]}"; do
        generated="$fixture/$relative"
        block="$(awk '/PANAMA THEME BEGIN/,/PANAMA THEME END/' "$generated")"

        grep -qF "@define-color view_bg_color $want_bg;" <<<"$block" \
            || fail "$relative did not take \"$theme_id\"'s background ($want_bg) for $scheme -- the block is not being regenerated from the theme"
        grep -qF "@define-color accent_bg_color $want_accent;" <<<"$block" \
            || fail "$relative did not take \"$theme_id\"'s accent ($want_accent) for $scheme"

        # Nothing outside the markers may move. That is the entire reason for
        # a marked block rather than a generated file.
        diff <(sed '/PANAMA THEME BEGIN/,/PANAMA THEME END/d' "$repo_dir/config/dot/$relative") \
             <(sed '/PANAMA THEME BEGIN/,/PANAMA THEME END/d' "$generated") >/dev/null \
            || fail "$relative changed OUTSIDE the markers -- the vendored theme's structural CSS is being rewritten"
    done
done

# The last render above was light, so this reads the light result: gtk-4.0's
# gtk.css shipped as a byte-for-byte copy of the dark one, which is how a light
# desktop kept drawing dark GTK4 windows.
light_bg="$(sed -n 's/^@define-color view_bg_color #\([0-9a-fA-F]\{6\}\);.*/\1/p' \
    "$fixture/gtk-4.0/gtk.css" | head -1)"
[[ -n "$light_bg" ]] || fail 'gtk-4.0/gtk.css has no view_bg_color after a light render'
(( 16#${light_bg:0:2} > 128 )) \
    || fail "gtk-4.0/gtk.css renders a DARK background (#$light_bg) in light mode -- the original bug"

printf 'gtk theme contract: PASS\n'
