#!/bin/bash
# wallp — unified wallpaper manager. See docs/superpowers/specs/.

set -u

# Expand a leading ~ or ~/ to $HOME. Leaves other paths unchanged.
expand_tilde() {
  case "$1" in
    "~") printf '%s\n' "$HOME" ;;
    "~/"*) printf '%s\n' "$HOME/${1#\~/}" ;;
    *) printf '%s\n' "$1" ;;
  esac
}

# Parse key=value conf into CONF_* globals. Ignores blanks and #-comments.
# Expands ~ in DEFAULT_* path values. Does not validate (see require_conf_keys).
CONF_THEME="" CONF_OUTPUT_H="" CONF_OUTPUT_V="" CONF_DEFAULT_H="" CONF_DEFAULT_V=""
parse_conf() {
  local file="$1" line key val
  while IFS= read -r line || [ -n "$line" ]; do
    case "$line" in ''|'#'*) continue ;; esac
    key="${line%%=*}"
    val="${line#*=}"
    case "$key" in
      THEME)     CONF_THEME="$val" ;;
      OUTPUT_H)  CONF_OUTPUT_H="$val" ;;
      OUTPUT_V)  CONF_OUTPUT_V="$val" ;;
      DEFAULT_H) CONF_DEFAULT_H="$(expand_tilde "$val")" ;;
      DEFAULT_V) CONF_DEFAULT_V="$(expand_tilde "$val")" ;;
    esac
  done < "$file"
}

conf_path() { printf '%s\n' "$HOME/.config/wallp/wallp.conf"; }

write_conf_template() {
  local path; path="$(conf_path)"
  mkdir -p "$(dirname "$path")"
  cat > "$path" <<'EOF'
# wallp config. Fill in real values, then re-run wallp.
# THEME is optional (defaults to sexy-splurge).
THEME=sexy-splurge
# Physical output names (see: swaymsg -t get_outputs / wlr-randr)
OUTPUT_H=DP-1
OUTPUT_V=DP-3
# Default wallpapers used by --restore when no saved state exists.
DEFAULT_H=~/Pictures/wallpapers/SFW/horizontal.png
DEFAULT_V=~/Pictures/wallpapers/SFW/vertical.png
EOF
}

# Hard-error if any required path/output key is empty. Returns 1 on first miss.
require_conf_keys() {
  local k var
  for k in OUTPUT_H OUTPUT_V DEFAULT_H DEFAULT_V; do
    var="CONF_$k"
    if [ -z "${!var}" ]; then
      echo "wallp: required config key '$k' is missing or empty in $(conf_path)" >&2
      return 1
    fi
  done
  return 0
}

# Returns: 0 ok, 1 invalid conf, 10 bootstrapped (caller should exit 0).
load_conf() {
  local path; path="$(conf_path)"
  if [ ! -f "$path" ]; then
    write_conf_template
    echo "wallp: generated config at $path — fill it in and re-run." >&2
    command -v notify-send >/dev/null 2>&1 && \
      notify-send -u normal "wallp" "Config generated at $path. Fill it in and re-run."
    return 10
  fi
  parse_conf "$path"
  [ -z "$CONF_THEME" ] && CONF_THEME="sexy-splurge"
  require_conf_keys || return 1
  return 0
}

theme_file() { printf '%s\n' "$HOME/.config/wallp/theme"; }

persist_theme() {
  local f; f="$(theme_file)"
  mkdir -p "$(dirname "$f")"
  printf '%s\n' "$1" > "$f"
}

# Precedence: flag arg > persisted file > CONF_THEME > sexy-splurge.
resolve_theme() {
  local flag="$1" f; f="$(theme_file)"
  if [ -n "$flag" ]; then printf '%s\n' "$flag"; return; fi
  if [ -s "$f" ]; then head -n1 "$f"; return; fi
  if [ -n "${CONF_THEME:-}" ]; then printf '%s\n' "$CONF_THEME"; return; fi
  printf '%s\n' "sexy-splurge"
}

# Maps logical output (H|V) to physical connector name from config.
output_for() {
  case "$1" in
    H) printf '%s\n' "$CONF_OUTPUT_H" ;;
    V) printf '%s\n' "$CONF_OUTPUT_V" ;;
    *) echo "wallp: unknown logical output '$1'" >&2; return 1 ;;
  esac
}

# Returns path to saved wall state for logical output (H|V).
wall_file_for() {
  case "$1" in
    H) printf '%s\n' "$HOME/.config/wallp/wall_h" ;;
    V) printf '%s\n' "$HOME/.config/wallp/wall_v" ;;
  esac
}

# Returns path to PID file for logical output (H|V).
pid_file_for() {
  case "$1" in
    H) printf '%s\n' "$HOME/.cache/wallp/H.pid" ;;
    V) printf '%s\n' "$HOME/.cache/wallp/V.pid" ;;
  esac
}

# Parse key=value conf into SET_* globals. Expands ~ in path values.
# Rejects unknown tokens (not H= or V=).
SET_H="" SET_V=""
parse_set_args() {
  local tok
  for tok in "$@"; do
    case "$tok" in
      H=*) SET_H="$(expand_tilde "${tok#H=}")" ;;
      V=*) SET_V="$(expand_tilde "${tok#V=}")" ;;
      *) echo "wallp: unknown --set argument '$tok' (expected H=<file> or V=<file>)" >&2; return 1 ;;
    esac
  done
  return 0
}

# Kill the swaybg recorded for a logical output, if its PID is still alive.
kill_output() {
  local logical="$1" pf pid; pf="$(pid_file_for "$logical")"
  [ -f "$pf" ] || return 0
  pid="$(cat "$pf")"
  if [ -n "$pid" ] && kill -0 "$pid" 2>/dev/null; then
    kill "$pid" 2>/dev/null
  fi
  rm -f "$pf"
}

# apply_output <H|V> <file>: set wallpaper for one output. rc1 = skipped.
apply_output() {
  local logical="$1" file="$2" output pf wf
  if [ ! -f "$file" ]; then
    echo "wallp: file not found, skipping $logical: $file" >&2
    return 1
  fi
  output="$(output_for "$logical")" || return 1
  kill_output "$logical"
  swaybg -o "$output" -i "$file" -m fill &
  pf="$(pid_file_for "$logical")"; mkdir -p "$(dirname "$pf")"
  printf '%s\n' "$!" > "$pf"
  wf="$(wall_file_for "$logical")"; mkdir -p "$(dirname "$wf")"
  printf '%s\n' "$file" > "$wf"
  return 0
}

main() {
  return 0
}

if [ "${BASH_SOURCE[0]}" = "$0" ]; then main "$@"; fi
