#!/bin/bash

# This script contains utility functions related to i3 workspaces.

# Ensure required functions exist
if ! command -v monitor_exist >/dev/null 2>&1; then
    echo "monitor_exist function is required but not found. Please source x.sh before i3.sh." 1>&2
    exit 1
fi

# Get the list of empty i3 workspaces.
# Usage: get_empty_i3_workspaces
get_empty_i3_workspaces() {
    set -euo pipefail
    i3-msg -t get_tree | jq -r '
        recurse(.nodes[]?) |
        select(.type == "workspace") |
        select(.name | test("^[^_].*")) |
        select(.nodes | length == 0) |
        .name
    '
}

# Check if the i3 workspace is empty.
# Usage: i3_workspace_is_empty <workspace_name>
i3_workspace_is_empty() {
    set -euo pipefail
    local workspace_name=${1:?Workspace name not set}
    local empty_workspace
    empty_workspace=$(get_empty_i3_workspaces)

    for workspace in $empty_workspace; do
        if [ "$workspace" = "$workspace_name" ]; then
            return 0
        fi
    done

    return 1
}

# Get a comma separated list of i3 workspace names and the output they are on.
# Usage: get_i3_workspaces
get_i3_workspaces() {
    set -euo pipefail
    i3-msg -t get_workspaces | jq -r '.[] | .name + "," + .output'
}

# Get a property of an i3 workspace.
# Usage: get_i3_workspace_prop <workspace_name> <property>
get_i3_workspace_prop() {
    set -euo pipefail
    local workspace_name=${1:?Workspace name not set}
    local prop=${2:?Property not set}
    i3-msg -t get_workspaces | jq -r ".[] | select(.name == \"$workspace_name\") | .$prop"
}

# Check if an i3 workspace exists.
# Usage: i3_workspace_exists <workspace_name>
i3_workspace_exists() {
    set -euo pipefail
    local workspace_name=${1:?Workspace name not set}
    if [[ -n "$(get_i3_workspace_prop "$workspace_name" name)" ]]; then
        return 0
    fi
    return 1
}

# Move an i3 workspace to a different monitor.
# Usage: move_i3_workspace <workspace_name> <monitor_name> [increment]
move_i3_workspace() {
    set -euo pipefail
    local workspace_name=${1:?Workspace name not set}
    local monitor_name=${2:?Monitor name not set}
    local increment=${3:-0}
    local new_workspace_name="$workspace_name"

    if ! i3_workspace_exists "$workspace_name"; then
        echo "Workspace $workspace_name not found" 1>&2
        return 1
    elif ! monitor_exist "$monitor_name"; then
        echo "Monitor $monitor_name not found" 1>&2
        return 1
    fi

    if [[ "$(get_i3_workspace_prop "$workspace_name" output)" == "$monitor_name" ]]; then
        echo "Workspace $workspace_name is already on monitor $monitor_name" 1>&2
        return 1
    fi

    if [[ "$workspace_name" =~ ^[0-9]+$ ]]; then
        new_workspace_name=$((workspace_name + increment))
    elif [ "$increment" -ne 0 ]; then
        echo "Workspace name is not an integer. Unable to increment/decrement." 1>&2
        return 1
    fi

    if i3_workspace_exists "$new_workspace_name"; then
        if [[ "$new_workspace_name" != "$workspace_name" ]]; then
            echo "Workspace $new_workspace_name already exists" 1>&2
            return 1
        fi
    fi

    echo "Moving workspace $workspace_name to monitor $monitor_name as $new_workspace_name"

    i3-msg "workspace $workspace_name" 1>/dev/null
    i3-msg "rename workspace $workspace_name to $new_workspace_name" 1>/dev/null
    i3-msg "move workspace to output $monitor_name" 1>/dev/null
}

# Move all workspaces to a specified monitor.
# Usage: move_nonexistent_i3_workspaces <monitor_name> [increment]
move_nonexistent_i3_workspaces() {
    set -euo pipefail
    local monitor_name=${1:?Monitor name not set}
    local increment=${2:-0}
    local workspaces
    workspaces=$(get_i3_workspaces)

    echo "Moving workspaces to monitor $monitor_name"

    for workspace in $workspaces; do
        local workspace_name
        local workspace_output
        workspace_name=$(echo "$workspace" | cut -d',' -f1)
        workspace_output=$(echo "$workspace" | cut -d',' -f2)

        if i3_workspace_is_empty "$workspace_name"; then
            echo "Skipping empty workspace $workspace_name"
            continue
        fi

        if ! monitor_exist "$workspace_output"; then
            move_i3_workspace "$workspace_name" "$monitor_name" "$increment"
        fi
    done
}
