#!/bin/bash

# omarchy:summary=Watch Hyprland monitor events and recover monitor toggles when a monitor is removed

SOCKET="$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock"
LOCK="${XDG_RUNTIME_DIR:-/tmp}/omarchy-monitor-clamshell.lock"

sync_clamshell() {
  (
    flock -n 9 || exit 0
    omarchy-hyprland-monitor-clamshell
  ) 9>"$LOCK"
}

sync_clamshell_after_monitor_change() {
  sync_clamshell

  (
    for delay in 1 3 7; do
      sleep "$delay"
      sync_clamshell
    done
  ) &
}

poll_clamshell_state() {
  while true; do
    sleep 2
    sync_clamshell
  done
}

# The internal panel is only ever disabled while a laptop is docked (lid shut
# with an external monitor active), so the reconciliation poll only has anything
# to reconcile in that window. Run it while docked, stop it when undocked, and
# never on a machine without a lid. Lid open/close itself is handled by the
# Hyprland "switch:*:Lid Switch" binds; this poll is the recovery backstop for
# drift those binds can miss (e.g. across suspend/resume).
poll_pid=""
sync_poll_state() {
  if omarchy-hw-laptop && omarchy-hyprland-monitor-external-active; then
    if [[ -z $poll_pid ]] || ! kill -0 "$poll_pid" 2>/dev/null; then
      poll_clamshell_state &
      poll_pid=$!
    fi
  elif [[ -n $poll_pid ]]; then
    kill "$poll_pid" 2>/dev/null
    poll_pid=""
  fi
}

sync_clamshell_after_monitor_change
sync_poll_state

# Process substitution (not a pipe) keeps this loop in the main shell, so
# sync_poll_state can start and stop the background poll as monitors come and go.
while read -r event; do
  case "$event" in
    monitoradded\>\>*|monitoraddedv2\>\>*)
      sync_clamshell_after_monitor_change
      sync_poll_state
      ;;
    monitorremoved\>\>*|monitorremovedv2\>\>*)
      sync_clamshell_after_monitor_change
      sync_poll_state
      ;;
  esac
done < <(socat -U - "UNIX-CONNECT:$SOCKET")
