#!/usr/bin/env bash
# SPDX-License-Identifier: GPL-2.0-or-later
#
# pocketds-screens — one-tap dual-screen layout helper for the AYANEO
# Pocket DS. Wraps `kscreen-doctor` with named presets for the upper
# DSI-1 + lower DSI-2 panel pair.
#
# Subcommands (each maps to a kscreen-doctor invocation):
#
#   both           Enable both panels in the canonical vertical-stack
#                  layout (DSI-1 primary, scale 1.5; DSI-2 below,
#                  scale 1.25; both rotated 90° CW).
#   top-only       Disable DSI-2; DSI-1 stays primary.
#   bottom-only    Disable DSI-1; promote DSI-2 to primary.
#   swap-primary   Toggle which panel holds the primary flag (the one
#                  Plasma puts the panel/taskbar on by default).
#   rotate-cw      Rotate both panels one step clockwise from current.
#   rotate-ccw     Same, counter-clockwise.
#   reset          Re-apply the canonical layout (alias for `both`).
#   status         Print current output state (kscreen-doctor -o).
#
# Output naming and modes come from the device tree; if the user
# renames their connectors, edit DSI_TOP/DSI_BOTTOM below.

set -euo pipefail

DSI_TOP="${POCKETDS_SCREENS_TOP:-DSI-1}"
DSI_BOTTOM="${POCKETDS_SCREENS_BOTTOM:-DSI-2}"

DSI_TOP_MODE="${POCKETDS_SCREENS_TOP_MODE:-1080x1920@120}"
DSI_TOP_SCALE="${POCKETDS_SCREENS_TOP_SCALE:-1.5}"
DSI_BOTTOM_MODE="${POCKETDS_SCREENS_BOTTOM_MODE:-768x1024@60}"
DSI_BOTTOM_SCALE="${POCKETDS_SCREENS_BOTTOM_SCALE:-1.25}"

# kscreen-doctor's "right" transform is the 90°-CW rotation we want
# for the portrait-mounted DSI panels (the same value KWin's JSON
# config calls "Rotated90"). "left" = 90° CCW = "Rotated270", etc.
TRANSFORM_DEFAULT="right"

if ! command -v kscreen-doctor >/dev/null 2>&1; then
    echo "pocketds-screens: kscreen-doctor not in PATH — install libkscreen" >&2
    exit 127
fi

usage() {
    sed -n '/^# pocketds-screens/,/^$/p' "$0" | sed 's/^# \{0,1\}//' >&2
    exit 64
}

apply_both() {
    kscreen-doctor \
        output."${DSI_TOP}".enable \
        output."${DSI_TOP}".mode."${DSI_TOP_MODE}" \
        output."${DSI_TOP}".scale."${DSI_TOP_SCALE}" \
        output."${DSI_TOP}".rotation."${TRANSFORM_DEFAULT}" \
        output."${DSI_TOP}".primary \
        output."${DSI_BOTTOM}".enable \
        output."${DSI_BOTTOM}".mode."${DSI_BOTTOM_MODE}" \
        output."${DSI_BOTTOM}".scale."${DSI_BOTTOM_SCALE}" \
        output."${DSI_BOTTOM}".rotation."${TRANSFORM_DEFAULT}" \
        output."${DSI_TOP}".position.0,0 \
        output."${DSI_BOTTOM}".position.283,720
}

apply_top_only() {
    kscreen-doctor \
        output."${DSI_TOP}".enable \
        output."${DSI_TOP}".primary \
        output."${DSI_BOTTOM}".disable
}

apply_bottom_only() {
    kscreen-doctor \
        output."${DSI_BOTTOM}".enable \
        output."${DSI_BOTTOM}".primary \
        output."${DSI_TOP}".disable
}

apply_swap_primary() {
    # `kscreen-doctor -j` prints the current config as JSON; pick which
    # output currently holds priority=1 and flip the other to primary.
    current_primary="$(kscreen-doctor -j 2>/dev/null \
        | grep -B1 '"priority": 1' \
        | grep '"name"' \
        | head -1 \
        | sed -E 's/.*"name":[[:space:]]*"([^"]+)".*/\1/')"

    if [ "${current_primary}" = "${DSI_TOP}" ]; then
        kscreen-doctor output."${DSI_BOTTOM}".primary
    else
        kscreen-doctor output."${DSI_TOP}".primary
    fi
}

# Rotation cycle: normal → right → inverted → left → normal …
ROT_CYCLE_CW=(normal right inverted left)
ROT_CYCLE_CCW=(normal left inverted right)

rotate_step() {
    local direction="$1"  # cw | ccw
    local -a cycle
    if [ "${direction}" = "cw" ]; then
        cycle=("${ROT_CYCLE_CW[@]}")
    else
        cycle=("${ROT_CYCLE_CCW[@]}")
    fi

    local current next
    for output in "${DSI_TOP}" "${DSI_BOTTOM}"; do
        current="$(kscreen-doctor -j 2>/dev/null \
            | python3 -c "
import json, sys
d = json.load(sys.stdin)
for o in d.get('outputs', []):
    if o.get('name') == '${output}':
        print(o.get('rotation', 'normal').lower()); break
" 2>/dev/null || echo "normal")"
        # Map kscreen-doctor numeric rotations (1/2/4/8) to names if
        # the JSON gave us an int — newer libkscreen does this.
        case "${current}" in
            1) current="normal" ;;
            2) current="right"  ;;
            4) current="inverted" ;;
            8) current="left" ;;
        esac

        # Walk the cycle to find the next step.
        next="${cycle[0]}"
        for i in "${!cycle[@]}"; do
            if [ "${cycle[$i]}" = "${current}" ]; then
                next="${cycle[(( (i + 1) % ${#cycle[@]} ))]}"
                break
            fi
        done
        kscreen-doctor output."${output}".rotation."${next}"
    done
}

cmd="${1:-}"
shift || :

case "${cmd}" in
    both|reset)       apply_both ;;
    top-only)         apply_top_only ;;
    bottom-only)      apply_bottom_only ;;
    swap-primary)     apply_swap_primary ;;
    rotate-cw)        rotate_step cw ;;
    rotate-ccw)       rotate_step ccw ;;
    status)           kscreen-doctor -o ;;
    ""|-h|--help)     usage ;;
    *)
        echo "pocketds-screens: unknown subcommand '${cmd}'" >&2
        usage
        ;;
esac
