#!/bin/bash

# omarchy:summary=Scale text everywhere — omarchy shell, GTK apps, and terminals
# omarchy:args=[size|reset]
# omarchy:examples=omarchy display text size | omarchy display text size 16 | omarchy display text size reset

# One knob for apparent text size across the desktop. It drives three settings
# in lockstep, all anchored to the shell default of 12px:
#   • the omarchy shell's font base-size (~/.config/omarchy/shell.toml [font])
#   • GNOME/GTK's text-scaling-factor    (12px -> 1.0, quantized so the GTK
#     interface font lands on a whole point size, so 16 -> 15pt/11pt = 1.3636)
#   • the terminal font point size       (12px -> 9pt, so terminal_pt = px * 9/12)
# The shell override layers on top of the active theme (so the size survives
# theme switches) and the shell watches the file, so shell text re-flows live.
# Accepts an integer from 9 to 20 (px).

MIN=9
MAX=20
GKEY_SCHEMA="org.gnome.desktop.interface"
GKEY_NAME="text-scaling-factor"

# Anchors: 12px shell base == factor 1.0 == 9pt terminal font.
TERM_DEFAULT_PT=9
SHELL_DEFAULT_PX=12

shell_config="$HOME/.config/omarchy/shell.toml"

usage() {
  echo "Usage: omarchy-display-text-size [size|reset]"
  echo "  (no args)   print the current text size, GTK factor, and terminal size"
  echo "  <size>      set text size in px ($MIN–$MAX); shell + GTK + terminals together"
  echo "  reset       return all three to their defaults (12px / 1.0 / 9pt)"
}

# ---- shell base-size: the rem root every shell type size derives from ----

# Print the base-size currently set under [font], or nothing if unset.
current_base_size() {
  [[ -f $shell_config ]] || return 0
  awk '
    /^[[:space:]]*\[/ { in_font = ($0 ~ /^[[:space:]]*\[font\]([[:space:]]|$)/); next }
    in_font && /^[[:space:]]*base-size[[:space:]]*=/ {
      v = $0
      sub(/^[^=]*=[[:space:]]*/, "", v)
      sub(/[[:space:]]*(#.*)?$/, "", v)
      print v
      exit
    }
  ' "$shell_config"
}

# Upsert base-size under [font]: replace it in place if present, insert it into
# an existing [font] section, or append a fresh [font] section otherwise. Other
# sections and keys in the user override are left untouched.
set_base_size() {
  local size="$1"
  mkdir -p "$(dirname "$shell_config")"

  if [[ ! -f $shell_config ]]; then
    printf '[font]\nbase-size = %s\n' "$size" >"$shell_config"
    return
  fi

  local tmp
  tmp="$(mktemp)"
  awk -v val="$size" '
    function emit_base() { print "base-size = " val; done = 1 }
    /^[[:space:]]*\[/ {
      if (in_font && !done) emit_base()
      in_font = ($0 ~ /^[[:space:]]*\[font\]([[:space:]]|$)/)
      print
      next
    }
    in_font && /^[[:space:]]*base-size[[:space:]]*=/ {
      if (!done) emit_base()
      next
    }
    { print }
    END {
      if (in_font && !done) emit_base()
      if (!done) {
        if (NR > 0) print ""
        print "[font]"
        emit_base()
      }
    }
  ' "$shell_config" >"$tmp"
  mv "$tmp" "$shell_config"
}

# Drop the base-size line, returning the shell to the theme/default size.
reset_base_size() {
  [[ -f $shell_config ]] || return 0
  local tmp
  tmp="$(mktemp)"
  awk '
    /^[[:space:]]*\[/ { in_font = ($0 ~ /^[[:space:]]*\[font\]([[:space:]]|$)/) }
    in_font && /^[[:space:]]*base-size[[:space:]]*=/ { next }
    { print }
  ' "$shell_config" >"$tmp"
  mv "$tmp" "$shell_config"
}

# ---- GTK text-scaling-factor ----

# Point size of the GTK interface font (font-name), used to quantize the
# scaling factor. Falls back to the GNOME default when unreadable.
gtk_font_pt() {
  local name pt
  name="$(gsettings get "$GKEY_SCHEMA" font-name 2>/dev/null)"
  pt="${name%\'}"
  pt="${pt##* }"
  if [[ $pt =~ ^[0-9]+(\.[0-9]+)?$ ]]; then
    echo "$pt"
  else
    echo 11
  fi
}

set_factor() {
  gsettings set "$GKEY_SCHEMA" "$GKEY_NAME" "$1" 2>/dev/null || true
}

# ---- terminal font point size ----

# px base-size -> terminal point size, rounded to the nearest integer.
term_pt_for() {
  awk -v s="$1" -v p="$TERM_DEFAULT_PT" -v b="$SHELL_DEFAULT_PX" \
    'BEGIN { printf "%d", int(s * p / b + 0.5) }'
}

# Set the font point size in every terminal config that exists. Family is left
# untouched — that is omarchy-font-set's job. Live-reload signals mirror
# omarchy-font-set; foot has no reload signal, so running instances are nudged.
set_terminal_size() {
  local pt="$1"

  if [[ -f ~/.config/alacritty/alacritty.toml ]]; then
    sed -i -E "s/^size[[:space:]]*=.*/size = $pt/" ~/.config/alacritty/alacritty.toml
  fi

  if [[ -f ~/.config/kitty/kitty.conf ]]; then
    sed -i -E "s/^font_size[[:space:]]+.*/font_size $pt.0/" ~/.config/kitty/kitty.conf
    pkill -USR1 kitty 2>/dev/null || true
  fi

  if [[ -f ~/.config/ghostty/config ]]; then
    sed -i -E "s/^font-size = .*/font-size = $pt/" ~/.config/ghostty/config
    pkill -SIGUSR2 ghostty 2>/dev/null || true
  fi

  if [[ -f ~/.config/foot/foot.ini ]]; then
    sed -i -E "s/(:size=)[0-9.]+/\1$pt/" ~/.config/foot/foot.ini
    # Foot has no config-reload signal, so a running instance keeps its startup
    # size until relaunched (new windows pick up the change). Nudge the user —
    # but reuse the same notification id (freedesktop replaces_id) so dragging
    # through several sizes refreshes one toast instead of stacking a pile.
    if pgrep -x foot >/dev/null 2>&1; then
      local id_file="${XDG_RUNTIME_DIR:-/tmp}/omarchy-display-text-size.foot-notif-id"
      local prev_id=""
      [[ -f $id_file ]] && read -r prev_id <"$id_file" 2>/dev/null
      local replace=()
      [[ $prev_id =~ ^[0-9]+$ ]] && replace=(-r "$prev_id")
      local new_id
      new_id="$(omarchy-notification-send \
        "Restart Foot to apply the new terminal font size" \
        "${replace[@]}" -p 2>/dev/null)" || true
      [[ $new_id =~ ^[0-9]+$ ]] && printf '%s\n' "$new_id" >"$id_file"
    fi
  fi
}

# Report the current terminal point size from whichever config we find first.
term_current_pt() {
  if [[ -f ~/.config/ghostty/config ]]; then
    grep -oP '^font-size = \K[0-9.]+' ~/.config/ghostty/config | head -1
  elif [[ -f ~/.config/alacritty/alacritty.toml ]]; then
    grep -oP '^size[[:space:]]*=[[:space:]]*\K[0-9.]+' ~/.config/alacritty/alacritty.toml | head -1
  elif [[ -f ~/.config/kitty/kitty.conf ]]; then
    grep -oP '^font_size[[:space:]]+\K[0-9.]+' ~/.config/kitty/kitty.conf | head -1
  elif [[ -f ~/.config/foot/foot.ini ]]; then
    grep -oP ':size=\K[0-9.]+' ~/.config/foot/foot.ini | head -1
  fi
}

case "${1:-}" in
  -h | --help)
    usage
    exit 0
    ;;
  "")
    cur="$(current_base_size)"
    size="${cur:-12 (default)}"
    factor="$(gsettings get "$GKEY_SCHEMA" "$GKEY_NAME" 2>/dev/null)"
    term="$(term_current_pt)"
    printf 'text size: %s px\ngtk text-scaling-factor: %s\nterminal font: %s pt\n' \
      "$size" "$factor" "${term:-n/a}"
    exit 0
    ;;
  reset | default)
    reset_base_size
    gsettings reset "$GKEY_SCHEMA" "$GKEY_NAME" 2>/dev/null || true
    set_terminal_size "$TERM_DEFAULT_PT"
    exit 0
    ;;
esac

size="$1"
if [[ ! $size =~ ^[0-9]+$ ]] || ((size < MIN || size > MAX)); then
  echo "Size must be an integer between $MIN and $MAX (px)." >&2
  usage >&2
  exit 1
fi

# Shell side: base-size in px (the omarchy shell's rem root).
set_base_size "$size"

# GTK side: multiplier anchored so 12px == 1.0, quantized so the interface
# font renders at a whole point size. Raw ratios yield fractional point sizes,
# which GTK4 menus clip at the ascenders on scale-1 monitors.
factor="$(awk -v s="$size" -v b="$SHELL_DEFAULT_PX" -v f="$(gtk_font_pt)" \
  'BEGIN { printf "%.4f", int(f * s / b + 0.5) / f }')"
set_factor "$factor"

# Terminal side: point size anchored so 12px == 9pt.
set_terminal_size "$(term_pt_for "$size")"
