#!/usr/bin/env bash

declare -A ws_windows=()
declare -A ws_name=()
declare -A ws_urgent=()
declare -A mon_active=()
focused_ws=""
focused_monitor=""
_state=""
_color=""

load_workspaces() {
  local raw
  raw=$(hyprctl -j workspaces 2>/dev/null) || return
  ws_windows=()
  ws_name=()
  while read -r id windows name; do
    ws_windows[$id]=$windows
    ws_name[$id]=$name
  done < <(printf '%s' "$raw" | jaq -jr '.[] | (.id | tostring), " ", (.windows | tostring), " ", .name, "\n"' 2>/dev/null)
}

load_monitors() {
  local raw
  raw=$(hyprctl -j monitors 2>/dev/null) || return
  mon_active=()
  focused_ws=""
  focused_monitor=""
  while read -r name active_id is_focused; do
    mon_active[$name]=$active_id
    if [ "$is_focused" = "true" ]; then
      focused_ws=$active_id
      focused_monitor=$name
    fi
  done < <(printf '%s' "$raw" | jaq -jr '.[] | .name, " ", (.activeWorkspace.id | tostring), " ", (.focused | tostring), "\n"' 2>/dev/null)
}

load_urgent() {
  local raw
  raw=$(hyprctl -j clients 2>/dev/null) || return
  ws_urgent=()
  while read -r wsid; do
    ws_urgent[$wsid]=1
  done < <(printf '%s' "$raw" | jaq -r '.[] | select(.urgent == true) | (.workspace.id | tostring)' 2>/dev/null)
}

ws_state_color() {
  local id=$1
  _state="empty"
  _color="grey"

  if [ "$id" = "$focused_ws" ]; then
    _state="focused"
  else
    local mon
    for mon in "${!mon_active[@]}"; do
      if [ "${mon_active[$mon]}" = "$id" ]; then
        _state="active"
        break
      fi
    done
    if [ "$_state" = "empty" ] && [ "${ws_windows[$id]:-0}" -gt 0 ]; then
      _state="running"
    fi
  fi

  if [ "$_state" != "empty" ]; then
    if [ "${ws_urgent[$id]:-0}" -eq 1 ]; then
      _color="red"
    else
      _color="blue"
    fi
  fi
}

ws_entry() {
  local id=$1 name=$2 target=$3 sep=${4:-false}
  ws_state_color "$id"
  printf '{"id":%s,"name":"%s","target":"%s","state":"%s","color":"%s","sep":%s}' \
    "$id" "$name" "$target" "$_state" "$_color" "$sep"
}

generate() {
  printf '['
  local first=true

  local neg_ids=() id
  for id in "${!ws_name[@]}"; do
    if [[ "$id" == -* ]] && [ "${ws_name[$id]}" != "special:magic" ]; then
      neg_ids+=("$id")
    fi
  done

  local has_neg=false
  if [ ${#neg_ids[@]} -gt 0 ]; then
    has_neg=true
    IFS=$'\n' sorted_neg=($(printf '%s\n' "${neg_ids[@]}" | sort -n)); unset IFS
    for id in "${sorted_neg[@]}"; do
      $first || printf ','
      first=false
      ws_entry "$id" "${ws_name[$id]}" "name:${ws_name[$id]}"
    done
  fi

  local first_pos=true
  for i in {1..9}; do
    $first || printf ','
    first=false
    if $first_pos && $has_neg; then
      ws_entry "$i" "$i" "$i" true
    else
      ws_entry "$i" "$i" "$i"
    fi
    first_pos=false
  done

  printf ']\n'
}

load_workspaces
load_monitors
load_urgent
generate

while read -r line; do
  event="${line%>>*}"
  data="${line#*>>}"
  case "$event" in
  "workspace")
    # data is the workspace name, not id — resolve to id for named workspaces
    focused_ws="$data"
    for _k in "${!ws_name[@]}"; do
      [ "${ws_name[$_k]}" = "$data" ] && { focused_ws="$_k"; break; }
    done
    unset "ws_urgent[$focused_ws]"
    [ -n "$focused_monitor" ] && mon_active[$focused_monitor]="$focused_ws"
    ;;
  "workspacev2")
    focused_ws="${data%%,*}"
    unset "ws_urgent[$focused_ws]"
    [ -n "$focused_monitor" ] && mon_active[$focused_monitor]="$focused_ws"
    ;;
  "focusedmon")
    focused_monitor="${data%%,*}"
    _wsname="${data#*,}"
    focused_ws="$_wsname"
    for _k in "${!ws_name[@]}"; do
      [ "${ws_name[$_k]}" = "$_wsname" ] && { focused_ws="$_k"; break; }
    done
    unset "ws_urgent[$focused_ws]"
    mon_active[$focused_monitor]="$focused_ws"
    ;;
  "urgent")
    wsid=$(hyprctl -j clients 2>/dev/null | jaq -r --arg addr "$data" '.[] | select(.address == $addr) | (.workspace.id | tostring)' 2>/dev/null)
    [ -n "$wsid" ] && ws_urgent[$wsid]=1
    ;;
  "createworkspace"*|"destroyworkspace"*|"moveworkspace"*)
    load_workspaces
    load_monitors
    ;;
  "openwindow"|"movewindow"*)
    load_workspaces
    ;;
  "closewindow")
    load_workspaces
    load_urgent
    ;;
  "monitor"*)
    load_monitors
    ;;
  esac
  generate
done < <(socat -u UNIX-CONNECT:"$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket2.sock" - | \
  rg --line-buffered "^(workspace|focusedmon|createworkspace|destroyworkspace|openwindow|closewindow|movewindow|moveworkspace|monitor|urgent)")
