#!/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

# ── hyprlock ─────────────────────────────────────────────────────────────────
# The lock screen. hyprlock is launched fresh on every lock (`pidof hyprlock ||
# hyprlock`), so it reads this file each time and needs no restart.
#
# It takes rgba(r, g, b, a) in DECIMAL, not hex, so the palette is expressed as
# "R, G, B" triples here rather than the hex used everywhere else. The two
# _HEX values are the exception: they sit inside Pango markup, where hyprlock
# wants ##rrggbb.
lock_dir="${XDG_CONFIG_HOME:-$HOME/.config}/hypr"
lock_template="$lock_dir/hyprlock.conf.template"

if [[ "$scheme" == "light" ]]; then
    lock_fg="55, 96, 191"        # #3760bf
    lock_muted="97, 114, 176"    # #6172b0
    lock_accent="46, 125, 233"   # #2e7de9
    lock_error="245, 42, 101"    # #f52a65
    lock_bg="225, 226, 231"      # #e1e2e7
    lock_field="208, 213, 227"   # #d0d5e3
    lock_muted_hex="6172b0"
    lock_error_hex="f52a65"
else
    lock_fg="200, 211, 245"      # #c8d3f5
    lock_muted="130, 139, 184"   # #828bb8
    lock_accent="130, 170, 255"  # #82aaff
    lock_error="255, 117, 127"   # #ff757f
    lock_bg="34, 36, 54"         # #222436
    lock_field="46, 47, 61"      # #2e2f3d
    lock_muted_hex="828bb8"
    lock_error_hex="ff757f"
fi

status_hyprlock="skipped"
if [[ -r "$lock_template" ]]; then
    # Written atomically: a lock triggered mid-write would otherwise read a
    # truncated config and fall back to hyprlock's own defaults, which is a
    # bright grey screen with none of this desktop's identity.
    if sed -e "s/@FG@/$lock_fg/g" \
           -e "s/@MUTED@/$lock_muted/g" \
           -e "s/@ACCENT@/$lock_accent/g" \
           -e "s/@ERROR@/$lock_error/g" \
           -e "s/@BG@/$lock_bg/g" \
           -e "s/@FIELD@/$lock_field/g" \
           -e "s/@MUTED_HEX@/$lock_muted_hex/g" \
           -e "s/@ERROR_HEX@/$lock_error_hex/g" \
           "$lock_template" >"$lock_dir/hyprlock.conf.tmp" 2>/dev/null \
        && mv "$lock_dir/hyprlock.conf.tmp" "$lock_dir/hyprlock.conf" 2>/dev/null; then
        status_hyprlock="written"
    else
        rm -f "$lock_dir/hyprlock.conf.tmp"
        status_hyprlock="failed"
    fi
fi

# ── 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" \
    --arg hyprlock "$status_hyprlock" \
    '{scheme: $scheme, kitty: $kitty, gtk: $gtk, btop: $btop, tmux: $tmux, hyprlock: $hyprlock}'
