#!/bin/bash
# shellcheck disable=SC1090

# This script is used to apply monitor profiles based on the connected monitors and USB devices.

# Source the utility functions
source ~/.local/share/dabruh/libs/bash/x.sh
source ~/.local/share/dabruh/libs/bash/i3.sh
source ~/.local/share/dabruh/libs/bash/usb.sh

# Function to check if USB devices exist
check_usb_devices() {
    local config_index=$1
    local config_file=$2

    local required_usb_device_list_count
    required_usb_device_list_count=$(yq e ".displayConfig[$config_index].requiredUsbDevices | length" "$config_file")

    for i in $(seq 0 $((required_usb_device_list_count - 1))); do
        local required_usb_devices
        required_usb_devices=$(yq e -o=j -I=0 ".displayConfig[$config_index].requiredUsbDevices[$i]" "$config_file")
        echo "Required USB devices: $required_usb_devices"

        local required_usb_device_group_list required_usb_device_group_list_count
        required_usb_device_group_list=$(echo "$required_usb_devices" | yq e -o=j -I=0 '.group')
        required_usb_device_group_list_count=$(echo "$required_usb_device_group_list" | yq e -o=j -I=0 '. | length')

        local require match
        require=$(echo "$required_usb_devices" | jq -r '.require')
        match=$(echo "$required_usb_devices" | jq -r '.match')

        local usb_devices=()
        for j in $(seq 0 $((required_usb_device_group_list_count - 1))); do
            local item
            item=$(echo "$required_usb_device_group_list" | jq -r ".[$j]")
            usb_devices+=("$item")
        done

        # Call the function with the array of USB devices
        if usb_devices_exist "$require" "$match" "${usb_devices[@]}" >/dev/null 2>&1; then
            return 0
        fi
    done

    return 1
}

# Function to check if monitors exist and return the group index for the first group that exists
check_monitors() {
    local config_index=$1
    local config_file=$2

    local required_output_list_count
    required_output_list_count=$(yq e ".displayConfig[$config_index].requiredOutputs | length" "$config_file")

    for i in $(seq 0 $((required_output_list_count - 1))); do
        local required_outputs
        required_outputs=$(yq e -o=j -I=0 ".displayConfig[$config_index].requiredOutputs[$i]" "$config_file")

        local required_output_group_list required_output_group_list_count
        required_output_group_list=$(echo "$required_outputs" | yq e -o=j -I=0 '.group')
        required_output_group_list_count=$(echo "$required_output_group_list" | yq e -o=j -I=0 '. | length')

        local monitors=()
        for j in $(seq 0 $((required_output_group_list_count - 1))); do
            local item
            item=$(echo "$required_output_group_list" | jq -r ".[$j]")
            monitors+=("$item")
        done

        # Call the function with the array of monitors
        if monitors_exist "${monitors[@]}" >/dev/null; then
            echo "$i" # Return the group index
            return 0
        fi
    done

    return 1
}

# Function to apply the display settings
apply_display_settings() {
    local config_index=$1
    local group_index=$2
    local config_file=$3

    local outputs
    outputs=$(yq e -o=j -I=0 ".displayConfig[$config_index].outputs" "$config_file")

    output_group=$(yq e -o=j -I=0  ".displayConfig[$config_index].requiredOutputs[$group_index].group" "$config_file")

    local output_list_count
    output_list_count=$(echo "$outputs" | yq e -o=j -I=0 '. | length')

    local args
    args=()

    for o in $(seq 0 $((output_list_count - 1))); do
        local output_name
        output_name=$(echo "$output_group" | jq -r ".[$o]")

        local mode rotate pos primary
        mode=$(echo "$outputs" | jq -r ".[$o].mode")
        rotate=$(echo "$outputs" | jq -r ".[$o].rotate")
        pos=$(echo "$outputs" | jq -r ".[$o].pos")
        primary=$(echo "$outputs" | jq -r ".[$o].primary // false")

        echo "Setting $output_name to $mode, $rotate, $pos, primary=$primary"

        args+=("--output" "$output_name" "--mode" "$mode" "--rotate" "$rotate" "--pos" "$pos")
        [ "$primary" = "true" ] && args+=("--primary")
    done

    echo "Running xrandr ${args[*]}"
    xrandr "${args[@]}"
}

# Function to parse and apply display configuration
apply_display_config() {
    local config_index=$1
    local config_file=$2

    check_usb_devices "$config_index" "$config_file" || return 1
    group_index=$(check_monitors "$config_index" "$config_file") || return 2
    apply_display_settings "$config_index" "$group_index" "$config_file"
}

main() {
    local config_file=$1
    local primary_monitor monitor_count profile_found=false
    primary_monitor=$(get_monitors primary | cut -d',' -f1)
    monitor_count=$(get_monitors connected | wc -l)
    echo "Monitors connected: $monitor_count"

    if [ "$monitor_count" -eq 1 ]; then
        echo "Applying laptop-only profile"
        xrandr --auto
        profile_found=true
    else
        local config_count
        config_count=$(yq e '.displayConfig | length' "$config_file")

        for i in $(seq 0 $((config_count - 1))); do
            name=$(yq e ".displayConfig[$i].name" "$config_file")
            echo "Trying profile #$i '$name'"
            if apply_display_config "$i" "$config_file"; then
                profile_found=true
                break
            else
                echo "Profile #$i '$name' failed with exit code $?" >&2
            fi
            echo
        done
    fi

    if ! "$profile_found"; then
        echo "No profile found"
        return 1
    fi

    disable_disconnected_monitors
    move_nonexistent_i3_workspaces "$primary_monitor" 10
    i3-msg restart >/dev/null
}

if [ "$0" = "${BASH_SOURCE[0]}" ]; then
    set -euo pipefail
    config_file="${1:-$HOME/.config/dabruh/xmonconf.yaml}"
    if ! [ -f "$config_file" ]; then
        echo "Config file not found: $config_file"
        exit 1
    fi
    main "$config_file"
fi
