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

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

if ! command -v jq >/dev/null 2>&1; then
  echo "error: jq not found; install with: sudo pacman -S jq" >&2
  exit 1
fi

mode="${1:-all}"
case "$mode" in
  all|single) ;;
  *)
    echo "usage: $(basename "$0") [all|single]" >&2
    exit 2
    ;;
esac

get_monitors_json() {
  local json
  json="$(mmsg get all-monitors 2>&1)"

  if ! jq -e '.monitors | type == "array"' >/dev/null 2>&1 <<<"$json"; then
    echo "error: failed to read monitors from mmsg:" >&2
    echo "$json" >&2
    exit 1
  fi

  printf '%s\n' "$json"
}

get_outputs() {
  get_monitors_json | jq -r '.monitors[].name'
}

get_active_monitor() {
  local json="$1"
  local active

  active="$(jq -r '.monitors[] | select(.active == true) | .name' <<<"$json" | head -n1)"

  if [[ -n "$active" && "$active" != "null" ]]; then
    echo "$active"
  else
    jq -r '.monitors[0].name' <<<"$json"
  fi
}

get_active_tag() {
  local mon="$1"
  get_monitors_json | jq -r --arg mon "$mon" '
    .monitors[]
    | select(.name == $mon)
    | (.active_tags[0] // 1)
  '
}

get_tag_clients() {
  local mon="$1"
  local tag="$2"

  get_monitors_json | jq -r --arg mon "$mon" --argjson tag "$tag" '
    .monitors[]
    | select(.name == $mon)
    | (.tags[] | select(.index == $tag) | .client_count) // 0
  '
}

get_total_clients() {
  local mon="$1"

  get_monitors_json | jq -r --arg mon "$mon" '
    .monitors[]
    | select(.name == $mon)
    | [.tags[].client_count]
    | add // 0
  '
}

dispatch() {
  mmsg dispatch "$1" >/dev/null
}

json="$(get_monitors_json)"

mapfile -t outputs < <(jq -r '.monitors[].name' <<<"$json")
out_count="${#outputs[@]}"

if (( out_count == 0 )); then
  echo "error: no monitors detected" >&2
  exit 1
fi

if (( out_count == 1 )); then
  echo "info: only one monitor detected by MangoWM, nothing to move"
  exit 0
fi

if (( out_count > 2 )); then
  echo "error: script supports max 2 monitors, found ${out_count}" >&2
  printf 'monitors:\n' >&2
  printf '  %s\n' "${outputs[@]}" >&2
  exit 2
fi

active="$(get_active_monitor "$json")"

target=""
for out in "${outputs[@]}"; do
  if [[ "$out" != "$active" ]]; then
    target="$out"
    break
  fi
done

if [[ -z "$target" ]]; then
  echo "error: failed to determine target monitor" >&2
  exit 1
fi

if [[ "$mode" == "single" ]]; then
  echo "move-single: active=${active} target=${target}"

  dispatch "focusmon,${active}"
  dispatch "tagmon,${target},1"

  echo "move-single: done"
  exit 0
fi

target_tag="$(get_active_tag "$target")"
source_total="$(get_total_clients "$active")"

if (( source_total == 0 )); then
  echo "info: no windows on active monitor (${active})"
  exit 0
fi

echo "move-all: active=${active} target=${target} target_tag=${target_tag} total=${source_total}"

moved=0

for tag in {1..9}; do
  while :; do
    before="$(get_tag_clients "$active" "$tag")"
    (( before > 0 )) || break

    dispatch "focusmon,${active}"

    # Select source tag.
    # If your Mango build uses tag masks instead of tag indexes for view,
    # this line may need changing.
    dispatch "view,${tag}"

    dispatch "tagcrossmon,${target_tag},${target}"

    dispatch "focusmon,${active}" || true

    after="$(get_tag_clients "$active" "$tag")"

    if (( after < before )); then
      (( moved += (before - after) ))
    else
      echo "warn: no progress on tag=${tag}; stopping this tag"
      break
    fi
  done
done

left="$(get_total_clients "$active")"
echo "move-all: done moved=${moved} left_on_source=${left} from=${active} to=${target} tag=${target_tag}"
