#!/usr/bin/env bash

# Propagates the colour scheme to applications that do not read the desktop
# portal.
#
# Most modern applications DO follow org.freedesktop.portal.Settings and need
# nothing from us: GTK4/libadwaita, Qt6, Chromium and Electron all read
# org.freedesktop.appearance color-scheme, which xdg-desktop-portal-gtk serves
# from gsettings. Panama sets that, so those follow automatically.
#
# Terminals are the notable exception -- they predate the standard and carry
# their own palettes. kitty is handled here.
#
# GTK3 is the other one. Under GNOME, gnome-settings-daemon publishes the theme
# over XSETTINGS; under Hyprland nothing does, so ~/.config/gtk-3.0/settings.ini
# is authoritative for GTK3 applications. Pinned to dark, it contradicted the
# scheme in light mode, so it is generated from a template here instead.
#
#   panama-theme-apps dark|light
#
# kitty gets it twice: the generated include file so terminals opened later
# start correct, and a live `set-colors` over its control socket so terminals
# already open change now. Without the second, a scheme change appears to do
# nothing until you open a new window.

set -euo pipefail

scheme="${1:-dark}"
case "$scheme" in
    dark|light) ;;
    *) printf 'usage: panama-theme-apps [dark|light]\n' >&2; exit 2 ;;
esac

# ── tmux ─────────────────────────────────────────────────────────────────────
# Generated like kitty's: tmux.conf sources current-theme.conf, and that file is
# machine state rather than configuration. Running servers are re-sourced so an
# open session changes now instead of at next launch -- tmux applies a
# source-file to every attached client immediately.
tmux_dir="${XDG_CONFIG_HOME:-$HOME/.config}/tmux"
tmux_theme="$tmux_dir/themes/tokyonight-moon.conf"
[[ "$scheme" == "light" ]] && tmux_theme="$tmux_dir/themes/tokyonight-day.conf"

status_tmux="skipped"
if [[ -r "$tmux_theme" ]]; then
    if cp "$tmux_theme" "$tmux_dir/current-theme.conf.tmp" 2>/dev/null \
        && mv "$tmux_dir/current-theme.conf.tmp" "$tmux_dir/current-theme.conf" 2>/dev/null; then
        status_tmux="written"
        # Only if a server is actually running; `tmux source-file` would
        # otherwise start one just to theme it.
        if command -v tmux >/dev/null 2>&1 && tmux has-session 2>/dev/null; then
            tmux source-file "$tmux_dir/current-theme.conf" 2>/dev/null \
                && status_tmux="applied to running sessions"
        fi
    else
        rm -f "$tmux_dir/current-theme.conf.tmp"
        status_tmux="failed"
    fi
fi

# ── btop ─────────────────────────────────────────────────────────────────────
# Only the color_theme line is rewritten, in place. btop OWNS btop.conf -- it
# rewrites the whole file on exit -- so the config is not symlinked into Panama
# and not replaced wholesale here; just this one value is edited, and btop keeps
# it on the next write.
#
# btop reads its theme once at startup, so a running instance keeps the old
# colours until it is restarted. That is acceptable for a monitor you open when
# you want it, and forcing a restart would kill a process the user is watching.
btop_conf="${XDG_CONFIG_HOME:-$HOME/.config}/btop/btop.conf"
btop_theme="tokyonight-moon"
[[ "$scheme" == "light" ]] && btop_theme="tokyonight-day"

status_btop="skipped"
if [[ -w "$btop_conf" ]]; then
    if sed -i "s|^color_theme *=.*|color_theme = \"$btop_theme\"|" "$btop_conf" 2>/dev/null; then
        status_btop="written"
    else
        status_btop="failed"
    fi
fi

# ── GTK ──────────────────────────────────────────────────────────────────────
# adw-gtk3, not Adwaita: no Adwaita GTK theme is installed on Fedora 44, and
# naming a theme that does not exist makes GTK fall back to its light default --
# which made dark mode silently produce light windows.
if [[ "$scheme" == "light" ]]; then
    gtk_theme="adw-gtk3"
    prefer_dark=0
else
    gtk_theme="adw-gtk3-dark"
    prefer_dark=1
fi

status_gtk="skipped"
for gtk_version in 3.0 4.0; do
    gtk_dir="${XDG_CONFIG_HOME:-$HOME/.config}/gtk-$gtk_version"
    template="$gtk_dir/settings.ini.template"
    [[ -r "$template" ]] || continue

    # Written atomically: a GTK application starting mid-write would otherwise
    # read a truncated file and fall back to defaults.
    if sed -e "s/@GTK_THEME@/$gtk_theme/" -e "s/@PREFER_DARK@/$prefer_dark/" "$template" \
        >"$gtk_dir/settings.ini.tmp" 2>/dev/null \
        && mv "$gtk_dir/settings.ini.tmp" "$gtk_dir/settings.ini" 2>/dev/null; then
        status_gtk="written"
    else
        rm -f "$gtk_dir/settings.ini.tmp"
        status_gtk="failed"
    fi
done

kitty_dir="${XDG_CONFIG_HOME:-$HOME/.config}/kitty"
theme_file="$kitty_dir/themes/tokyonight-moon.conf"
[[ "$scheme" == "light" ]] && theme_file="$kitty_dir/themes/tokyonight-day.conf"

status_kitty="skipped"
if [[ -r "$theme_file" ]]; then
    # Written atomically: kitty may read this while a new window is starting.
    if cp "$theme_file" "$kitty_dir/current-theme.conf.tmp" 2>/dev/null \
        && mv "$kitty_dir/current-theme.conf.tmp" "$kitty_dir/current-theme.conf" 2>/dev/null; then
        status_kitty="written"
    fi

    # Live-apply to running terminals. kitty appends its PID to the socket name
    # from listen_on, so there is one socket per instance -- "unix:@mykitty"
    # alone reaches nothing, which is exactly how this looked like remote
    # control being disabled when it was not.
    if command -v kitty >/dev/null 2>&1 && command -v ss >/dev/null 2>&1; then
        applied=0
        while read -r socket; do
            [[ -n "$socket" ]] || continue
            if kitty @ --to "unix:@${socket#@}" set-colors --all --configured "$theme_file" >/dev/null 2>&1; then
                applied=$((applied + 1))
            fi
        done < <(ss -xl 2>/dev/null | grep -oE '@mykitty[^[:space:]]*' | sort -u)
        (( applied > 0 )) && status_kitty="applied to $applied"
    fi
fi

# Every target reports what actually happened. A helper that says only
# "kitty: applied" while silently skipping three other applications is how a
# half-applied theme goes unnoticed.
jq -cn \
    --arg scheme "$scheme" \
    --arg kitty "$status_kitty" \
    --arg gtk "$status_gtk" \
    --arg btop "$status_btop" \
    --arg tmux "$status_tmux" \
    '{scheme: $scheme, kitty: $kitty, gtk: $gtk, btop: $btop, tmux: $tmux}'
