#!/usr/bin/env bash
set -euo pipefail
VCP_INPUT=0x60
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/monitor-input"
CACHE_FILE="$CACHE_DIR/displays"
CACHE_TTL=60

# Output one line per DDC-capable display: BUS	MODEL	MFG (from ddcutil detect, cached for CACHE_TTL seconds).
list_ddc_displays() {
  mkdir -p "$CACHE_DIR"
  local now ts
  now=$(date +%s)
  ts=$(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0)
  if [[ -s "$CACHE_FILE" ]] && (( ts + CACHE_TTL > now )); then
    cat "$CACHE_FILE"
    return
  fi
  ddcutil detect 2>/dev/null | awk '
    /^Display [0-9]+$/ { bus=""; model=""; mfg=""; next }
    /^Invalid display|^   DDC communication failed/ { next }
    /^   I2C bus:/ { if (match($0, /i2c-[0-9]+/)) bus=substr($0, RSTART+4, RLENGTH-4); next }
    /^      Mfg id:[[:space:]]+/ { mfg=substr($0, index($0,":")+1); gsub(/^[[:space:]]+/, "", mfg); next }
    /^      Model:[[:space:]]+/ { model=substr($0, index($0,":")+1); gsub(/^[[:space:]]+/, "", model); next }
    /^   VCP version:/ { if (bus != "") print bus "\t" model "\t" mfg }
  ' | tee "$CACHE_FILE"
}

# Resolve DISP (bus number or name substring) to bus number. Exits 1 if not found or ambiguous.
# When DISP is numeric, use it directly (no slow ddcutil detect).
resolve_display() {
  local disp="$1"
  if [[ "$disp" =~ ^[0-9]+$ ]]; then
    echo "$disp"
    return 0
  fi
  local bus r
  bus=$(list_ddc_displays | awk -v disp="$disp" '
    BEGIN { d = tolower(disp); found = 0 }
    {
      if (index(tolower($2), d) || index(tolower($3), d)) {
        if (found) exit 2
        found = $1
      }
    }
    END { if (found) print found; exit (found ? 0 : 1) }
  ')
  r=$?
  [[ $r -eq 2 ]] && { echo "monitor-input: '$disp' matches multiple displays (use bus number)" >&2; return 1; }
  [[ $r -eq 0 && -n "$bus" ]] || { echo "monitor-input: no DDC display matching '$disp'" >&2; return 1; }
  echo "$bus"
}

# Map input name to VCP 0x60 value (common assignments; use hex for others).
input_to_hex() {
  case "$(echo "$1" | tr '[:upper:]' '[:lower:]')" in
    dp|dp1)   echo "0x0f" ;;
    dp2)      echo "0x10" ;;
    hdmi|hdmi1) echo "0x11" ;;
    hdmi2)    echo "0x12" ;;
    0x*)      echo "$1" ;;
    *)       echo "monitor-input: unknown input '$1' (use dp, dp1, dp2, hdmi, hdmi1, hdmi2, or 0xNN)" >&2; return 1 ;;
  esac
}

case "${1:-}" in
  list)
    echo "Bus	Model	Mfg"
    list_ddc_displays
    ;;
  *)
    [[ -n "${1:-}" ]] || { echo "Usage: monitor-input list | monitor-input <display> get|set [input]" >&2; exit 1; }
    case "${2:-}" in
      get)
        bus=$(resolve_display "$1") || exit 1
        exec ddcutil --bus "$bus" getvcp "$VCP_INPUT"
        ;;
      set)
        [[ -n "${3:-}" ]] || { echo "Usage: monitor-input <display> set <input>" >&2; exit 1; }
        bus=$(resolve_display "$1") || exit 1
        hex=$(input_to_hex "$3") || exit 1
        exec ddcutil --bus "$bus" setvcp "$VCP_INPUT" "$hex"
        ;;
      *)
        echo "Usage: monitor-input list" >&2
        echo "       monitor-input <display> get" >&2
        echo "       monitor-input <display> set <input>" >&2
        echo "  display: bus number (e.g. 23) or name match (e.g. benq, zowie, lg, 34GL750)" >&2
        echo "  input:   dp, dp1, dp2, hdmi, hdmi1, hdmi2, or 0xNN" >&2
        exit 1
        ;;
    esac
    ;;
esac
