#!/bin/bash
# Apply theme colors from ~/.config/colors.conf to all deployed dotfile configs.
#
# Guards:
#   - Refuses if any deployed config is symlinked back to ~/Dotfiles (old-style
#     install), to prevent theme changes from propagating into the git repo.
#   - When configs are copied into ~/.config (new-style install), overwrites
#     those copies in-place.
#
# Tracks last-applied state in ~/.config/colors.state so only changed colors
# trigger replacements. Run again after re-install to re-apply your theme.
#
# Usage: ~/apply-theme.sh [/path/to/colors.conf]

set -euo pipefail

DOTFILES="${DOTFILES:-$HOME/Dotfiles}"
COLORS_CONF="${1:-$HOME/.config/colors.conf}"
STATE_FILE="$HOME/.config/colors.state"

# Hardcoded defaults — the values baked into every source file in the repo.
# Used to bootstrap colors.state on first run after a fresh install.
BOOT_TEXT="D6ABAB"
BOOT_BG="1A1A1A"
BOOT_HIGHLIGHT="E40046"
BOOT_DARK="5018DD"
BOOT_RED="F50505"

# "dotfiles_relative_path|absolute_deployed_path"
USER_FILES=(
    "starship.toml|$HOME/.config/starship.toml"
    "yazi/theme.toml|$HOME/.config/yazi/theme.toml"
    "desktopenvs/hyprland/hypr/hyprland.conf|$HOME/.config/hypr/hyprland.conf"
    "desktopenvs/hyprland/hypr/hyprtoolkit.conf|$HOME/.config/hypr/hyprtoolkit.conf"
    "desktopenvs/hyprland/hypr/hyprlock.conf|$HOME/.config/hypr/hyprlock.conf"
    "desktopenvs/hyprland/kitty/current-theme.conf|$HOME/.config/kitty/current-theme.conf"
    "desktopenvs/hyprland/kitty/kitty.conf|$HOME/.config/kitty/kitty.conf"
    "desktopenvs/hyprland/kitty/themes/cyberqueer.conf|$HOME/.config/kitty/themes/cyberqueer.conf"
    "desktopenvs/hyprland/waybar/style.css|$HOME/.config/waybar/style.css"
    "desktopenvs/hyprland/wofi/style.css|$HOME/.config/wofi/style.css"
    "desktopenvs/hyprland/walker/themes/cyberqueer.css|$HOME/.config/walker/themes/cyberqueer.css"
    "desktopenvs/hyprland/nwg-panel/menu-start.css|$HOME/.config/nwg-panel/menu-start.css"
    "desktopenvs/hyprlua/astal-menu/style/_colors.css|$HOME/.config/astal-menu/style/_colors.css"
    "desktopenvs/hyprland/vicinae/cyberqueer.toml|$HOME/.config/vicinae/cyberqueer.toml"
    "desktopenvs/hyprland/scripts/onscreenkb.sh|$HOME/.config/scripts/onscreenkb.sh"
    "desktopenvs/hyprland/spicetify/Themes/cli-cyberqueer/color.ini|$HOME/.config/spicetify/Themes/cli-cyberqueer/color.ini"
    "desktopenvs/hyprland/spicetify/Themes/matte-cyberqueer/color.ini|$HOME/.config/spicetify/Themes/matte-cyberqueer/color.ini"
    "desktopenvs/hyprland/ulauncher/user-themes/cyberqueer/manifest.json|$HOME/.config/ulauncher/user-themes/cyberqueer/manifest.json"
    "desktopenvs/hyprland/ulauncher/user-themes/cyberqueer/theme.css|$HOME/.config/ulauncher/user-themes/cyberqueer/theme.css"
    "desktopenvs/hyprland/ulauncher/user-themes/cyberqueer/generated.css|$HOME/.config/ulauncher/user-themes/cyberqueer/generated.css"
    "desktopenvs/hyprland/Vencord/themes/cyberqueer.theme.css|$HOME/.config/Vencord/themes/cyberqueer.theme.css"
    "desktopenvs/hyprland/Vencord/themes/system24/theme/flavors/cyberqueer.theme.css|$HOME/.config/Vencord/themes/system24/theme/flavors/cyberqueer.theme.css"
    "qt-themes/cyberqueer/style.qss|$HOME/.config/qt6ct/qss/style.qss"
    "qt-themes/cyberqueer/cyberqueer.conf|$HOME/.config/qt6ct/colors/cyberqueer.conf"
    "qt-themes/cyberqueer/style-plugin/CyberQueerStyle.cpp|$DOTFILES/qt-themes/cyberqueer/style-plugin/CyberQueerStyle.cpp"
    "qt-themes/cyberqueer/hyprpolkitagent-qt.conf|$HOME/.config/systemd/user/hyprpolkitagent.service.d/qt-theme.conf"
    "desktopenvs/niri/niri/config.kdl|$HOME/.config/niri/config.kdl"
)

# System-owned paths — sed is run via sudo
SYS_FILES=(
    "etc-ly-config.ini|/etc/ly/config.ini"
    "etc-greetd/regreet.css|/etc/greetd/regreet.css"
    "gtk-themes/cyberqueer/gtk-3.0/gtk.css|/usr/share/themes/cyberqueer/gtk-3.0/gtk.css"
    "gtk-themes/cyberqueer/gtk-4.0/gtk.css|/usr/share/themes/cyberqueer/gtk-4.0/gtk.css"
)

# ---------------------------------------------------------------------------

die() { echo "error: $*" >&2; exit 1; }

parse_colors() {
    local file="$1"
    [[ -f "$file" ]] || die "not found: $file"
    while IFS='=' read -r key val; do
        key="${key%%[[:space:]]*}"
        [[ "$key" =~ ^[[:space:]]*# || -z "$key" ]] && continue
        val="${val%%#*}"
        val="${val//[[:space:]]/}"
        val="${val^^}"
        printf '%s=%s\n' "$key" "$val"
    done < "$file"
}

# Returns 0 if any path component of $1 is a symlink pointing into DOTFILES
links_into_dotfiles() {
    local path="$1"
    while [[ "${#path}" -gt 1 ]]; do
        if [[ -L "$path" ]]; then
            local target
            target=$(readlink -f "$path" 2>/dev/null) || break
            [[ "$target" == "$DOTFILES"/* || "$target" == "$DOTFILES" ]] && return 0
        fi
        [[ "$path" == "$HOME" ]] && break
        path=$(dirname "$path")
    done
    return 1
}

# Run sed -i with optional command prefix (e.g. "sudo").
# Called as: do_replace <file> [sudo]
do_replace() {
    local file="$1"
    shift  # remaining "$@" is either empty or "sudo"
    for key in "${CHANGED_KEYS[@]}"; do
        local old="${OLD[$key]:-}"
        local new="${NEW[$key]}"
        [[ -z "$old" || "$old" == "$new" ]] && continue
        "$@" sed -i "s/${old}/${new}/gI" "$file"
    done
}

# ---------------------------------------------------------------------------
# Bootstrap state on fresh install (deployed files still have default colors)

if [[ ! -f "$STATE_FILE" ]]; then
    cat > "$STATE_FILE" <<EOF
COLOR_TEXT=$BOOT_TEXT
COLOR_BG=$BOOT_BG
COLOR_HIGHLIGHT=$BOOT_HIGHLIGHT
COLOR_DARK=$BOOT_DARK
COLOR_RED=$BOOT_RED
EOF
    echo "Created $STATE_FILE with default CyberQueer colors"
fi

# ---------------------------------------------------------------------------
# Symlink guard — refuse if any deployed path traces back to the git repo

SYMLINKED=()
for entry in "${USER_FILES[@]}"; do
    deployed="${entry#*|}"
    [[ -e "$deployed" ]] || continue
    links_into_dotfiles "$deployed" && SYMLINKED+=("$deployed")
done

if [[ ${#SYMLINKED[@]} -gt 0 ]]; then
    echo "error: the following deployed configs are symlinked back to $DOTFILES:"
    printf '  %s\n' "${SYMLINKED[@]}"
    cat <<'EOF'

Modifying these would write theme changes directly into the git repo.
Re-install using setup/modules/Desktop-Enviroments/hyprland-new.sh,
which copies configs instead of symlinking them.

To convert a single directory manually:
  cp -rL ~/.config/hypr /tmp/hypr && rm -rf ~/.config/hypr && mv /tmp/hypr ~/.config/hypr
EOF
    exit 1
fi

# ---------------------------------------------------------------------------
# Load and diff colors

declare -A OLD NEW

while IFS='=' read -r k v; do OLD[$k]="$v"; done < <(parse_colors "$STATE_FILE")
while IFS='=' read -r k v; do NEW[$k]="$v"; done < <(parse_colors "$COLORS_CONF")

CHANGED_KEYS=()
for key in "${!NEW[@]}"; do
    [[ "${OLD[$key]:-}" != "${NEW[$key]}" ]] && CHANGED_KEYS+=("$key")
done

if [[ ${#CHANGED_KEYS[@]} -eq 0 ]]; then
    echo "No color changes — nothing to do."
    exit 0
fi

echo "Changes to apply:"
for key in "${CHANGED_KEYS[@]}"; do
    printf '  %-20s #%s → #%s\n' "$key" "${OLD[$key]:-?}" "${NEW[$key]}"
done
echo

# ---------------------------------------------------------------------------
# Apply to user files

u_ok=0; u_skip=0
for entry in "${USER_FILES[@]}"; do
    deployed="${entry#*|}"
    if [[ ! -f "$deployed" ]]; then
        u_skip=$((u_skip + 1))
        continue
    fi
    do_replace "$deployed"
    u_ok=$((u_ok + 1))
done

# ---------------------------------------------------------------------------
# Apply to system files (sudo)

s_ok=0; s_skip=0
for entry in "${SYS_FILES[@]}"; do
    deployed="${entry#*|}"
    if [[ ! -f "$deployed" ]]; then
        s_skip=$((s_skip + 1))
        continue
    fi
    if do_replace "$deployed" sudo; then
        s_ok=$((s_ok + 1))
    else
        echo "  SKIP (sudo failed): $deployed"
        s_skip=$((s_skip + 1))
    fi
done

# ---------------------------------------------------------------------------
# Reload services that read their config once at start

POLKIT_DROP="$HOME/.config/systemd/user/hyprpolkitagent.service.d/qt-theme.conf"
if [[ -f "$POLKIT_DROP" ]] && systemctl --user is-active --quiet hyprpolkitagent 2>/dev/null; then
    systemctl --user daemon-reload
    systemctl --user restart hyprpolkitagent
    echo "Restarted hyprpolkitagent with updated colors."
fi

# Rebuild Qt style plugin if its source was updated
PLUGIN_BUILD="$DOTFILES/qt-themes/cyberqueer/style-plugin/build.sh"
if [[ -f "$PLUGIN_BUILD" ]]; then
    if bash "$PLUGIN_BUILD"; then
        echo "Rebuilt cyberqueer Qt style plugin."
    else
        echo "Warning: Qt style plugin rebuild failed — relaunch apps will still use old colors."
    fi
fi

# ---------------------------------------------------------------------------
# Persist state

cp "$COLORS_CONF" "$STATE_FILE"

echo "User files:   $u_ok updated, $u_skip not installed."
[[ $((s_ok + s_skip)) -gt 0 ]] && echo "System files: $s_ok updated, $s_skip not installed."
echo "State saved → $STATE_FILE"
