#!/bin/sh

set -eu

usage() {
  echo "Usage: $(basename $0) [user_with_monitors_xml]"
}

call_gdbus() {
  local user_with_monitors_xml
  user_with_monitors_xml="$1"; shift

  if [ "$user_with_monitors_xml" = "$(id -nu)" ]; then
    "$@" >/dev/null || return 1
  else
    if ! user_id=$(id -u "$user_with_monitors_xml"); then
      echo "Could not determine user id for ${user_with_monitors_xml}" >&2
      return 1
    fi
    sudo -n -u "$user_with_monitors_xml" \
      env "DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/${user_id}/bus" "$@" \
        >/dev/null || return 1
  fi
}

user_with_monitors_xml=${1:-}
if [ -z "$user_with_monitors_xml" -a -n "${DISPLAY:-}" ]; then
  user_with_monitors_xml="$(id -nu)"
fi

current_user_list=$(who | awk '$2 ~ /^:/ { print $1 }' | xargs -n 1)

# find out user from the current sessions
if [ -z "$user_with_monitors_xml" ]; then
  current_user_count="$(printf "%s" "$current_user_list" | wc -w)"
  if [ "$current_user_count" -eq 0 ]; then
    echo 'No current display users' >&2
    usage >&2
    exit 1
  elif [ "$current_user_count" -gt 1 ]; then
    echo "Multiple current users, choose from: ${current_user_list}" >&2
    usage >&2
    exit 1
  fi
  user_with_monitors_xml="$current_user_list"
fi

user_home=$(getent passwd | awk -F: -v user="$user_with_monitors_xml" '
                              $1 == user { print $6 }
                            ')
if [ -z "$user_home" ]; then
  echo "Could not determine user '$user_with_monitors_xml' home directory" >&2
  exit 1
fi

if ! this_hostname="$(hostname -s)" || [ -z "$this_hostname" ]; then
  echo 'Could not determine hostname' >&2
  exit 1
fi
monitors_xml_path="${user_home}/.config/monitors-${this_hostname}.xml"

if printf "%s" "$current_user_list" | grep -qw "$user_with_monitors_xml"; then
  rm -f "$monitors_xml_path"
  # if user has a session, ask gnome-shell/mutter to write monitors.xml
  if ! call_gdbus "$user_with_monitors_xml" \
         gdbus call --session \
                    --dest=org.gnome.Mutter.DisplayConfig \
                    --object-path /org/gnome/Mutter/DisplayConfig \
                    --method org.gnome.Mutter.DisplayConfig.ApplyMonitorsConfig \
                    0 3 '[]' '[]'; then
    echo 'Error when running gdbus call' >&2
    exit 1
  fi
fi

# give a bit of time for monitors.xml to appear in the filesystem
monitors_xml_written=false
for i in $(seq 3); do
  if [ -s "$monitors_xml_path" ]; then
    sleep 1
    monitors_xml_written=true
    break
  fi
  sleep "$i"
done

if ! $monitors_xml_written \
     || ! monitors_xml=$(cat "$monitors_xml_path" 2>/dev/null); then
  echo "Could not read monitor settings from ${monitors_xml_path}" >&2
  echo 'Maybe try sudo?' >&2
  exit 1
fi
monitors_xml="${monitors_xml}
"

if ! json=$(jq -n --arg monitors_xml "$monitors_xml" \
              '.["monitors.xml"] = $monitors_xml'); then
  echo 'Could not create json to send' >&2
  exit 1
fi

if [ -r /etc/puavo/ldap/dn -a -r /etc/puavo/ldap/password ]; then
  prr_auth_args='--user-etc --writable'
elif klist >/dev/null 2>&1; then
  prr_auth_args='--user-krb --writable'
elif [ -e /run/puavo/nbd-server ]; then
  prr_auth_args='--user-bootserver'
else
  echo 'Could not figure out how to authenticate to Puavo' >&2
  exit 1
fi

status=0

url="/v3/devices/${this_hostname}/monitors"
if ! puavo-rest-request "$url" --post $prr_auth_args -- \
       --data-binary "$json" -H 'Content-Type: application/json'; then
  echo 'Error in sending monitors data to Puavo' >&2
  status=1
else
  # XXX The intention of puavo-change-host-state is to immediately change
  # XXX the current (global) host state to use the new monitors.xml.
  # XXX For new desktop sessions (for all users) this should work,
  # XXX however gdm needs some wakeup call to read the new monitors.xml
  # XXX and we yet do not know how.
  sudo -n puavo-change-host-state --monitors-xml "$monitors_xml" || true
  if mountpoint -q /state; then
    puavo-update-client --auto >/dev/null 2>&1 || true
  fi
fi

exit $status
