#!/bin/bash

# omarchy:summary=Cycle the current active workspace through the dwindle, scrolling, and floating layouts
# omarchy:args=[back]

# Layout changes replace one notification instead of stacking a new one for
# each press, so cycling through the layouts leaves a single, current one.
notify_layout() {
  local state="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/workspace-layout-notification"
  local last id
  [[ -r $state ]] && read -r last <"$state"
  if id=$(omarchy-notification-send -p -r "${last:-0}" -g 󱂬 "$1") && [[ $id =~ ^[0-9]+$ ]]; then
    mkdir -p "$(dirname "$state")" && printf '%s\n' "$id" >"$state"
  fi
}

DIRECTION=${1:-next}
if [[ $DIRECTION != "next" && $DIRECTION != "back" ]]; then
  echo "Usage: omarchy-hyprland-workspace-layout-toggle [back]" >&2
  exit 1
fi

ACTIVE_WORKSPACE=$(hyprctl activeworkspace -j | jq -r '.id')
# Named workspaces report a negative id, and Hyprland reads a leading "-" as a
# selector relative to the current workspace: targeting one lands on workspace 1
# and reconfigures that instead.
[[ $ACTIVE_WORKSPACE =~ ^[0-9]+$ ]] || exit 1
MODES_DIR="${XDG_STATE_HOME:-$HOME/.local/state}/omarchy/workspace-layouts"
MODE_FILE="$MODES_DIR/$ACTIVE_WORKSPACE.lua"

CURRENT_MODE=$(omarchy-hyprland-workspace-layout-current)

if [[ $DIRECTION == "back" ]]; then
  case "$CURRENT_MODE" in
    dwindle) NEW_MODE=floating ;;
    floating) NEW_MODE=scrolling ;;
    *) NEW_MODE=dwindle ;;
  esac
else
  case "$CURRENT_MODE" in
    dwindle) NEW_MODE=scrolling ;;
    scrolling) NEW_MODE=floating ;;
    *) NEW_MODE=dwindle ;;
  esac
fi

APPLY="o.workspace_mode({ workspace = \"$ACTIVE_WORKSPACE\", mode = \"$NEW_MODE\" })"

# Dwindle is Hyprland's name for it; the menu and the bar call it tiling.
if [[ $NEW_MODE == "dwindle" ]]; then
  LABEL=tiling
else
  LABEL=$NEW_MODE
fi

# Saving a mode that did not apply would leave the file naming one layout while
# the screen shows another, and restore it at the next login.
APPLIED=0
if hyprctl eval "$APPLY" >/dev/null 2>&1; then
  APPLIED=1
fi

if (( ! APPLIED )); then
  notify_layout "Workspace layout needs a Hyprland reload"
elif [[ $NEW_MODE == "$(omarchy-hyprland-workspace-layout-default)" ]] && rm -f "$MODE_FILE"; then
  # Cycled onto the default, a workspace goes back to following it, so a later
  # change of the default reaches it too.
  notify_layout "Workspace layout set to $LABEL"
elif mkdir -p "$MODES_DIR" && printf '%s\n' "$APPLY" >"$MODE_FILE"; then
  notify_layout "Workspace layout set to $LABEL"
else
  # The mode is on screen but nothing will bring it back, and the next press
  # reads the mode from this file, so say so rather than counting it as set.
  notify_layout "Workspace layout set to $LABEL but could not be saved"
fi

# The bar shows the focused workspace's layout, and the dock shows on floating ones.
if (( APPLIED )); then
  omarchy-shell -q omarchy.workspaces refresh
  omarchy-shell -q omarchy.dock refresh
fi

# A workspace starting to float sets up its titlebars as the mode applies. The
# titlebar plugin itself is only loaded while the config loads, so the first
# floating workspace of a session still needs a reload to bring it in.
if (( APPLIED )) && [[ $NEW_MODE == "floating" ]] && ! hyprctl plugin list -j 2>/dev/null | jq -e 'any(.[]?; .name == "hyprbars")' >/dev/null 2>&1; then
  hyprctl reload >/dev/null
fi
