#!/usr/bin/env bash
set -euo pipefail

mode="${1:-}"
if [[ "$mode" != "toggle-ms" && "$mode" != "cycle" && "$mode" != "nav-next" && "$mode" != "nav-prev" && "$mode" != "nav-up" && "$mode" != "nav-down" && "$mode" != "move-left" && "$mode" != "move-right" && "$mode" != "move-up" && "$mode" != "move-down" && "$mode" != "resize-grow-h" && "$mode" != "resize-shrink-h" ]]; then
  printf 'Usage: %s {toggle-ms|cycle|nav-next|nav-prev|nav-up|nav-down|move-left|move-right|move-up|move-down|resize-grow-h|resize-shrink-h}\n' "${0##*/}" >&2
  exit 2
fi

if ! command -v hyprctl >/dev/null 2>&1; then
  echo "hyprctl not found" >&2
  exit 1
fi

active_json="$(hyprctl -j activeworkspace 2>/dev/null || true)"
if [[ -z "$active_json" ]]; then
  echo "failed to query active workspace" >&2
  exit 1
fi

active_name=""
active_id=""
if command -v jq >/dev/null 2>&1; then
  active_name="$(printf '%s' "$active_json" | jq -r '.name // empty')"
  active_id="$(printf '%s' "$active_json" | jq -r '.id // empty')"
else
  active_name="$(printf '%s' "$active_json" | sed -n 's/.*"name":"\([^"]*\)".*/\1/p')"
  active_id="$(printf '%s' "$active_json" | sed -n 's/.*"id":\([0-9-]\+\).*/\1/p')"
fi

if [[ -z "$active_name" && -z "$active_id" ]]; then
  echo "could not parse active workspace" >&2
  exit 1
fi

if [[ -n "$active_name" && ! "$active_name" =~ ^[0-9]+$ ]]; then
  ws_selector="name:$active_name"
  ws_key="name:$active_name"
else
  ws_id="${active_id:-$active_name}"
  ws_selector="$ws_id"
  ws_key="id:$ws_id"
fi

state_file="${XDG_RUNTIME_DIR:-/tmp}/hypr-workspace-layout-state"

get_state() {
  local key="$1"
  if [[ -f "$state_file" ]]; then
    awk -F '\t' -v k="$key" '$1 == k {v = $2} END {print v}' "$state_file"
  fi
}

set_state() {
  local key="$1"
  local layout="$2"
  local tmp
  tmp="$(mktemp "${state_file}.XXXXXX")"

  if [[ -f "$state_file" ]]; then
    awk -F '\t' -v k="$key" '$1 != k {print $1 "\t" $2}' "$state_file" > "$tmp"
  fi

  printf '%s\t%s\n' "$key" "$layout" >> "$tmp"
  mv "$tmp" "$state_file"
}

current_layout="$(get_state "$ws_key")"
if [[ -z "$current_layout" ]]; then
  if command -v jq >/dev/null 2>&1; then
    current_layout="$(printf '%s' "$active_json" | jq -r '.tiledLayout // empty')"
  else
    current_layout="$(printf '%s' "$active_json" | sed -n 's/.*"tiledLayout":"\([^"]*\)".*/\1/p')"
  fi
  current_layout="${current_layout:-master}"
fi

if [[ "$mode" == "toggle-ms" ]]; then
  if [[ "$current_layout" == "master" ]]; then
    next_layout="scrolling"
  else
    next_layout="master"
  fi
elif [[ "$mode" == "cycle" ]]; then
  layouts=(dwindle master scrolling monocle)
  next_layout="${layouts[0]}"

  for i in "${!layouts[@]}"; do
    if [[ "${layouts[$i]}" == "$current_layout" ]]; then
      next_layout="${layouts[$(((i + 1) % ${#layouts[@]}))]}"
      break
    fi
  done
elif [[ "$mode" == "nav-next" ]]; then
  if [[ "$current_layout" == "scrolling" ]]; then
    hyprctl dispatch layoutmsg "focus r" >/dev/null
  else
    hyprctl dispatch cyclenext >/dev/null
  fi
  exit 0
elif [[ "$mode" == "nav-prev" ]]; then
  if [[ "$current_layout" == "scrolling" ]]; then
    hyprctl dispatch layoutmsg "focus l" >/dev/null
  else
    hyprctl dispatch cyclenext prev >/dev/null
  fi
  exit 0
elif [[ "$mode" == "nav-down" ]]; then
  if [[ "$current_layout" == "scrolling" ]]; then
    hyprctl dispatch layoutmsg "focus d" >/dev/null
  elif [[ "$current_layout" == "master" ]]; then
    hyprctl dispatch layoutmsg addmaster >/dev/null
  else
    hyprctl dispatch cyclenext >/dev/null
  fi
  exit 0
elif [[ "$mode" == "nav-up" ]]; then
  if [[ "$current_layout" == "scrolling" ]]; then
    hyprctl dispatch layoutmsg "focus u" >/dev/null
  elif [[ "$current_layout" == "master" ]]; then
    hyprctl dispatch layoutmsg removemaster >/dev/null
  else
    hyprctl dispatch cyclenext prev >/dev/null
  fi
  exit 0
elif [[ "$mode" == "move-left" ]]; then
  if [[ "$current_layout" == "scrolling" ]]; then
    hyprctl dispatch layoutmsg "swapcol l" >/dev/null
  elif [[ "$current_layout" != "monocle" ]]; then
    hyprctl dispatch movewindow l >/dev/null
  fi
  exit 0
elif [[ "$mode" == "move-right" ]]; then
  if [[ "$current_layout" == "scrolling" ]]; then
    hyprctl dispatch layoutmsg "swapcol r" >/dev/null
  elif [[ "$current_layout" != "monocle" ]]; then
    hyprctl dispatch movewindow r >/dev/null
  fi
  exit 0
elif [[ "$mode" == "move-up" ]]; then
  [[ "$current_layout" != "monocle" ]] && hyprctl dispatch movewindow u >/dev/null
  exit 0
elif [[ "$mode" == "move-down" ]]; then
  [[ "$current_layout" != "monocle" ]] && hyprctl dispatch movewindow d >/dev/null
  exit 0
elif [[ "$mode" == "resize-grow-h" ]]; then
  if [[ "$current_layout" == "scrolling" ]]; then
    hyprctl dispatch layoutmsg "colresize +0.1" >/dev/null
  elif [[ "$current_layout" != "monocle" ]]; then
    hyprctl dispatch resizeactive 25 0 >/dev/null
  fi
  exit 0
elif [[ "$mode" == "resize-shrink-h" ]]; then
  if [[ "$current_layout" == "scrolling" ]]; then
    hyprctl dispatch layoutmsg "colresize -0.1" >/dev/null
  elif [[ "$current_layout" != "monocle" ]]; then
    hyprctl dispatch resizeactive -25 0 >/dev/null
  fi
  exit 0
fi

hyprctl keyword workspace "$ws_selector,layout:$next_layout" >/dev/null
set_state "$ws_key" "$next_layout"

# Best-effort notification so layout switches are visible immediately.
hyprctl notify -1 1800 "rgb(8bd5ca)" "Layout: ${next_layout} (${ws_selector})" >/dev/null 2>&1 || true
