#!/usr/bin/env bash
# clockmost-theme — apply / swap a whole-desktop theme in one move.
#
#   clockmost-theme list             themes available (+ which is active)
#   clockmost-theme current          print the active theme
#   clockmost-theme apply <name>     apply everything: palette, shape, fonts, kitty
#   clockmost-theme revert           restore the state from before the first apply
#
# A theme lives in  <repo>/themes/<name>/  as:
#   theme.toml            metadata + required packages + font roles
#   noctalia-palette.json Material-3 palette  -> ~/.config/noctalia/palettes/
#   noctalia.toml         settings.toml shape deltas
#   cosmic.toml           COSMIC shape (radii / gaps / hint / frosted)
#   kitty.conf            kitty type + surface block
#
# Colours flow palette -> Noctalia templates (GTK/Qt/kitty/btop) -> the
# noctalia-cosmic-theme bridge -> COSMIC. This tool owns the palette *file*,
# the non-colour shape, the fonts, and triggering everything.
set -euo pipefail

REPO="$(cd "$(dirname "$(readlink -f "$0")")/.." && pwd)"
THEMES="$REPO/themes"
LIB="$REPO/lib"
STATE="${XDG_STATE_HOME:-$HOME/.local/state}/clockmost-theme"
NOCTALIA_SETTINGS="${XDG_STATE_HOME:-$HOME/.local/state}/noctalia/settings.toml"
NOCTALIA_PALETTES="${XDG_CONFIG_HOME:-$HOME/.config}/noctalia/palettes"
COSMIC_TK="${XDG_CONFIG_HOME:-$HOME/.config}/cosmic/com.system76.CosmicTk/v1"
KITTY_CONF="${XDG_CONFIG_HOME:-$HOME/.config}/kitty/kitty.conf"
SYNC_UNIT="cosmic-noctalia-sync.service"
MARK_BEGIN="# >>> clockmost-theme >>>"
MARK_END="# <<< clockmost-theme <<<"

say()  { printf '\033[1;33m::\033[0m %s\n' "$*"; }
warn() { printf '\033[1;35m!!\033[0m %s\n' "$*" >&2; }
die()  { printf '\033[1;31mxx\033[0m %s\n' "$*" >&2; exit 1; }

tget() { # tget <toml> <python-expr over `d`>   -> value or empty
  python3 - "$1" "$2" <<'PY' 2>/dev/null || true
import sys, tomllib
d = tomllib.loads(open(sys.argv[1]).read())
try:
    v = eval(sys.argv[2])
    print("" if v is None else v)
except Exception:
    pass
PY
}

# ── baseline snapshot (first apply only) ─────────────────────────────────────
snapshot_baseline() {
  [ -e "$STATE/baseline" ] && return 0
  say "first run — snapshotting current desktop state to $STATE/baseline"
  mkdir -p "$STATE/baseline"
  cp -a "$NOCTALIA_SETTINGS" "$STATE/baseline/noctalia-settings.toml" 2>/dev/null || true
  cp -a "$KITTY_CONF"        "$STATE/baseline/kitty.conf"             2>/dev/null || true
  cp -a "$COSMIC_TK"         "$STATE/baseline/CosmicTk"               2>/dev/null || true
  for v in Dark Light Dark.Builder Light.Builder; do
    d="$HOME/.config/cosmic/com.system76.CosmicTheme.$v/v2"
    [ -d "$d" ] && cp -a "$d" "$STATE/baseline/CosmicTheme.$v" || true
  done
  noctalia msg color-scheme-get > "$STATE/baseline/noctalia-scheme" 2>/dev/null || true
}

# ── steps ───────────────────────────────────────────────────────────────────
step_preflight() {
  local dir="$1" pkgs
  pkgs=$(tget "$dir/theme.toml" "' '.join(d.get('requires',{}).get('packages',[]))")
  [ -z "$pkgs" ] && return 0
  local missing=()
  for p in $pkgs; do pacman -Qq "$p" &>/dev/null || missing+=("$p"); done
  [ ${#missing[@]} -gt 0 ] && warn "missing packages (install for the full look): ${missing[*]}"
  return 0
}

step_noctalia_palette() {
  local dir="$1" name="$2"
  [ -f "$dir/noctalia-palette.json" ] || return 0
  mkdir -p "$NOCTALIA_PALETTES"
  install -m644 "$dir/noctalia-palette.json" "$NOCTALIA_PALETTES/$name.json"
  say "noctalia palette -> $name"
  noctalia msg color-scheme-set custom "$name" >/dev/null
}

step_noctalia_settings() {
  # Shape + fonts + wallpaper, all via a whole-file tomllib rewrite (no regex on
  # the live config). Mutate a copy, validate, commit only if still valid.
  local dir="$1" work
  [ -f "$NOCTALIA_SETTINGS" ] || { warn "no noctalia settings.toml — skipping"; return 0; }
  work=$(mktemp)
  cp "$NOCTALIA_SETTINGS" "$work"
  python3 "$LIB/noctalia-settings.py" "$work" "$dir" --wallpaper || {
    warn "settings mutation failed — live config untouched"; rm -f "$work" "$work.clockmost-bak"; return 1
  }
  rm -f "$work.clockmost-bak"

  if noctalia config validate "$work" 2>&1 | grep -qE 'ERROR|✗ Config is invalid'; then
    warn "merged noctalia config is invalid — keeping the current settings.toml"
    noctalia config validate "$work" 2>&1 | grep -E 'ERROR' >&2 || true
    rm -f "$work"; return 1
  fi
  # sanity: section count must not shrink
  local before after
  before=$(grep -c '^\[' "$NOCTALIA_SETTINGS"); after=$(grep -c '^\[' "$work")
  if [ "$after" -lt "$before" ]; then
    warn "refusing settings.toml with $after sections (was $before) — kept current"
    rm -f "$work"; return 1
  fi
  mv "$work" "$NOCTALIA_SETTINGS"
  say "noctalia settings updated ($after sections)"
}

step_cosmic_shape() {
  local dir="$1"
  [ -f "$dir/cosmic.toml" ] || return 0
  python3 "$LIB/cosmic-shape.py" "$dir/cosmic.toml"
}

step_cosmic_fonts() {
  local dir="$1" ui mono
  ui=$(tget "$dir/theme.toml" "d['fonts']['ui']")
  mono=$(tget "$dir/theme.toml" "d['fonts']['mono']")
  [ -d "$COSMIC_TK" ] || { warn "no CosmicTk dir — skipping COSMIC fonts"; return 0; }
  _tk_font() { printf '(\n    family: "%s",\n    weight: Normal,\n    stretch: Normal,\n    style: Normal,\n)' "$1"; }
  [ -n "$ui" ]   && _tk_font "$ui"   > "$COSMIC_TK/interface_font"
  [ -n "$mono" ] && _tk_font "$mono" > "$COSMIC_TK/monospace_font"
  say "COSMIC fonts -> ui:$ui mono:$mono  (re-login for full repaint)"
}

step_cosmic_colours() {
  rm -f "$HOME/.config/noctalia/generated/.applied-sha"
  systemctl --user start "$SYNC_UNIT" 2>/dev/null \
    && say "COSMIC colour bridge ran" \
    || warn "could not run $SYNC_UNIT — COSMIC colours may lag"
}

step_kitty() {
  local dir="$1"
  [ -f "$dir/kitty.conf" ] || return 0
  mkdir -p "$(dirname "$KITTY_CONF")"
  touch "$KITTY_CONF"
  local tmp; tmp=$(mktemp)
  sed "/^${MARK_BEGIN}$/,/^${MARK_END}$/d" "$KITTY_CONF" | sed -e :a -e '/^\n*$/{$d;N;ba}' > "$tmp"
  {
    cat "$tmp"
    printf '\n%s\n' "$MARK_BEGIN"
    cat "$dir/kitty.conf"
    printf '%s\n' "$MARK_END"
  } > "$KITTY_CONF"
  rm -f "$tmp"
  grep -q 'include .*noctalia' "$KITTY_CONF" || printf '\ninclude themes/noctalia.conf\n' >> "$KITTY_CONF"
  pkill -SIGUSR1 -x kitty 2>/dev/null || true
  say "kitty block updated"
}


reload_noctalia() { noctalia msg config-reload >/dev/null 2>&1 || true; }

# ── commands ────────────────────────────────────────────────────────────────
cmd_list() {
  local active; active=$(cmd_current)
  for d in "$THEMES"/*/; do
    local n; n=$(basename "$d")
    [ "$n" = "$active" ] && printf '  \033[1;33m* %s\033[0m' "$n" || printf '    %s' "$n"
    local t; t=$(tget "$d/theme.toml" "d['meta'].get('description','')")
    [ -n "$t" ] && printf '  — %s' "$t"
    printf '\n'
  done
}

cmd_current() {
  local s; s=$(noctalia msg color-scheme-get 2>/dev/null || true)
  case "$s" in custom\ *) echo "${s#custom }";; *) echo "(none)";; esac
}

cmd_apply() {
  local name="${1:-}"; [ -n "$name" ] || die "usage: clockmost-theme apply <name>"
  local dir="$THEMES/$name"
  [ -d "$dir" ] || die "no theme '$name' in $THEMES"
  [ -f "$dir/theme.toml" ] || die "$name has no theme.toml"

  snapshot_baseline
  say "applying theme: $name"
  step_preflight            "$dir"
  step_noctalia_palette     "$dir" "$name"
  step_noctalia_settings    "$dir"
  step_cosmic_shape         "$dir"
  step_cosmic_fonts         "$dir"
  step_cosmic_colours
  step_kitty                "$dir"
  reload_noctalia
  say "done — '$name' applied. Log out / back in for COSMIC apps to fully repaint."
}

cmd_revert() {
  [ -d "$STATE/baseline" ] || die "no baseline snapshot — nothing to revert to"
  say "restoring pre-theme baseline"
  [ -f "$STATE/baseline/noctalia-settings.toml" ] && cp -a "$STATE/baseline/noctalia-settings.toml" "$NOCTALIA_SETTINGS"
  [ -f "$STATE/baseline/kitty.conf" ]             && cp -a "$STATE/baseline/kitty.conf" "$KITTY_CONF"
  [ -d "$STATE/baseline/CosmicTk" ]               && cp -aT "$STATE/baseline/CosmicTk" "$COSMIC_TK"
  for v in Dark Light Dark.Builder Light.Builder; do
    [ -d "$STATE/baseline/CosmicTheme.$v" ] \
      && cp -aT "$STATE/baseline/CosmicTheme.$v" "$HOME/.config/cosmic/com.system76.CosmicTheme.$v/v2"
  done
  if [ -f "$STATE/baseline/noctalia-scheme" ]; then
    read -r src sel < "$STATE/baseline/noctalia-scheme"
    [ -n "${src:-}" ] && noctalia msg color-scheme-set "$src" "$sel" >/dev/null 2>&1 || true
  fi
  step_cosmic_colours
  reload_noctalia
  say "baseline restored. Log out / back in for COSMIC."
}

case "${1:-}" in
  list)    cmd_list ;;
  current) cmd_current ;;
  apply)   shift; cmd_apply "$@" ;;
  revert)  cmd_revert ;;
  ""|-h|--help)
    sed -n '2,14p' "$0" | sed 's/^# \{0,1\}//' ;;
  *) die "unknown command: $1  (list | current | apply <name> | revert)" ;;
esac
