#!/usr/bin/env bash

# What closing the lid should do.
#
#   panama-lid status    what this machine would do right now, as JSON
#   panama-lid guard     hold the inhibitor while clamshell use is possible
#
# The rule is one sentence: closing the lid should suspend, UNLESS there is an
# external monitor, in which case the machine is docked and should keep working.
#
# The implementation is deliberately not a lid watcher. logind already handles
# the lid perfectly well; what it cannot do is notice that an external display
# makes a closed lid mean something different, because its own "docked" test
# looks for an ACPI docking station that modern hardware does not have.
#
# So Panama does not take the lid over. It holds a `handle-lid-switch`
# inhibitor while an external monitor is connected, and releases it when the
# last one goes away. logind does everything else, which has three properties
# worth having:
#
#   * Nothing has to watch the lid, and no polling loop exists.
#   * If this ever fails or is killed, the inhibitor is released and the
#     machine goes back to logind's default. The failure mode is "a docked
#     laptop suspends", not "the lid does nothing at all", which is the failure
#     mode a logind drop-in would have.
#   * Locking before sleep is already handled: hypridle's before_sleep_cmd
#     runs `loginctl lock-session`, so a suspend from a closed lid is a locked
#     suspend without anything here being involved.
#
# Started and stopped by services/LidPolicy.qml on display topology changes.
#
# NOT YET VERIFIED ON A LAPTOP. The logic and the inhibitor are testable on any
# machine and are covered by tests/setup/lid-contract, but the end-to-end
# behavior of closing a real lid on a docked machine needs a machine with a
# lid. Everything here fails toward logind's default, so the untested path is
# "keeps working while docked" rather than anything that could strand a session.

set -uo pipefail

PANAMA_PATH="${PANAMA_PATH:-$HOME/.local/share/Panama}"
HW="$PANAMA_PATH/bin/panama-hw"

answer() { "$@" && printf 'true' || printf 'false'; }

cmd_status() {
    local inhibited=false
    systemd-inhibit --list 2>/dev/null | grep -q 'panama-lid' && inhibited=true
    printf '{"laptop":%s,"lidClosed":%s,"externalMonitor":%s,"clamshell":%s,"inhibited":%s}\n' \
        "$(answer "$HW" laptop)" \
        "$(answer "$HW" lid-closed)" \
        "$(answer "$HW" external-monitor)" \
        "$(answer "$HW" clamshell)" \
        "$inhibited"
}

# Holds the inhibitor for as long as it runs. Exits immediately, holding
# nothing, when this machine has no reason to want one -- a desktop has no lid
# to inhibit and an undocked laptop should suspend normally.
cmd_guard() {
    "$HW" laptop || exit 0
    "$HW" external-monitor || exit 0

    exec systemd-inhibit \
        --what=handle-lid-switch \
        --who=panama-lid \
        --why="An external display is connected, so a closed lid is a docked machine rather than one being put away" \
        --mode=block \
        sleep infinity
}

# The internal panel's connector name, from the compositor: eDP, LVDS and
# DSI are built in, everything else arrived through a cable -- the same rule
# panama-hw and LidPolicy use.
internal_connector() {
    hyprctl -j monitors all 2>/dev/null \
        | jq -r '[.[] | select(.name | test("^(eDP|LVDS|DSI)"; "i"))][0].name // empty'
}

# Bound to the lid switch by keybinds.lua. Closing a DOCKED lid turns the
# internal panel off, so nothing renders inside a closed shell and no
# workspace strands on an invisible output; an undocked lid does nothing here
# because logind is already suspending the machine. Failure direction: if the
# disable never runs, the panel stays lit inside the shell -- wasteful, not
# harmful.
cmd_close() {
    "$HW" laptop || exit 0
    "$HW" external-monitor || exit 0
    local internal
    internal="$(internal_connector)"
    [[ -n "$internal" ]] || exit 0
    hyprctl eval "hl.monitor({ output = \"$internal\", disable = true })" >/dev/null
}

# Re-enable on open, preferring what the person chose for this panel in
# Settings (the same displays store monitors.lua reads at startup) and
# falling back to the panel's preferred mode.
cmd_open() {
    "$HW" laptop || exit 0
    local internal entry mode scale
    internal="$(internal_connector)"
    [[ -n "$internal" ]] || exit 0
    entry="$(jq -c --arg name "$internal" '.displays[$name] // empty' \
        "${XDG_CONFIG_HOME:-$HOME/.config}/panama/settings.json" 2>/dev/null)"
    if [[ -n "$entry" ]]; then
        mode="$(jq -r '.mode' <<<"$entry")"
        scale="$(jq -r '.scale' <<<"$entry")"
        hyprctl eval "hl.monitor({ output = \"$internal\", mode = \"$mode\", position = \"auto\", scale = $scale })" >/dev/null
    else
        hyprctl eval "hl.monitor({ output = \"$internal\", mode = \"preferred\", position = \"auto\", scale = \"auto\" })" >/dev/null
    fi
}

case "${1:-status}" in
    status) cmd_status ;;
    guard)  cmd_guard ;;
    close)  cmd_close ;;
    open)   cmd_open ;;
    -h|--help)
        cat <<'USAGE'
usage: panama-lid [status|guard|close|open]

  status   what closing the lid would do right now, as JSON
  guard    hold a handle-lid-switch inhibitor while an external display is
           connected; exits immediately on a machine that needs none
  close    docked lid closed: turn the internal panel off (bound to the lid
           switch by keybinds.lua); does nothing undocked
  open     lid opened: turn the internal panel back on, restoring the mode
           and scale chosen in Settings
USAGE
        ;;
    *) printf 'panama-lid: unknown command: %s\n' "$1" >&2; exit 2 ;;
esac
