#!/bin/bash

print_usage() {
    echo "Usage:"
    echo "  collect [-o] [-m] [-i] range file"
    echo "  Examples:"
    echo "    collect 1,3 file.txt             # Copy lines to clipboard"
    echo "    collect -o 1,3 file.txt          # Print lines to stdout"
    echo "    collect -m 1,3:5,7:9,9 file.txt  # Multiple ranges, separated by ':'"
    echo "    collect -i 1,3 file.txt          # Inverse selection (all except lines 1-3)"
    exit 1
}

validate_range() {
    local range=$1
    local file=$2
    local total_lines=$(wc -l < "$file")

    if ! [[ $range =~ ^[0-9]+(,[0-9]+)?$ ]]; then
        echo "Error: Invalid range format '$range'. Expected format: n or n,m"
        return 1
    fi

    IFS=',' read -r start end <<< "$range"
    if [ -z "$end" ]; then
        end=$start
    fi

    if [ "$start" -gt "$end" ]; then
        echo "Error: Invalid range '$range'. Start line must be less than or equal to end line."
        return 1
    fi

    if [ "$start" -eq 0 ] || [ "$end" -gt "$total_lines" ]; then
        echo "Error: Range '$range' is out of bounds. File has $total_lines lines."
        return 1
    fi

    return 0
}

process_range() {
    local range=$1
    local file=$2
    local inverse=$3
    local total_lines=$(wc -l < "$file")

    if [ "$inverse" = true ]; then
        IFS=',' read -r start end <<< "$range"
        if [ -z "$end" ]; then
            end=$start
        fi

        if [ "$start" -gt 1 ]; then
            sed -n "1,$((start-1))p" "$file"
        fi

        if [ "$end" -lt "$total_lines" ]; then
            sed -n "$((end+1)),$((total_lines))p" "$file"
        fi
    else
        sed -n "${range}p" "$file"
    fi
}

if [ "$#" -lt 2 ]; then
    print_usage
fi

output_mode=false
multi_range=false
inverse_mode=false

while getopts "omi" opt; do
    case ${opt} in
        o )
            output_mode=true
            ;;
        m )
            multi_range=true
            ;;
        i )
            inverse_mode=true
            ;;
        \? )
            print_usage
            ;;
    esac
done
shift $((OPTIND -1))

if [ "$#" -ne 2 ]; then
    print_usage
fi

ranges=$1
file=$2

if [ ! -f "$file" ]; then
    echo "Error: File '$file' does not exist."
    exit 1
fi

if [ "$multi_range" = true ]; then
    IFS=':' read -ra RANGE_ARRAY <<< "$ranges"
    for range in "${RANGE_ARRAY[@]}"; do
        if ! validate_range "$range" "$file"; then
            exit 1
        fi
    done
else
    if ! validate_range "$ranges" "$file"; then
        exit 1
    fi
fi

if [ "$output_mode" = false ]; then
    if ! command -v xclip &> /dev/null; then
        echo "Error: xclip could not be found. Please install xclip."
        exit 1
    fi
fi

if [ "$inverse_mode" = true ] && [ "$multi_range" = true ]; then
    echo "Error: Inverse selection (-i) cannot be used with multiple ranges (-m)"
    exit 1
fi

temp_file=$(mktemp)

if [ "$multi_range" = true ]; then
    for range in "${RANGE_ARRAY[@]}"; do
        process_range "$range" "$file" false >> "$temp_file"
    done
else
    process_range "$ranges" "$file" "$inverse_mode" >> "$temp_file"
fi

if [ "$output_mode" = true ]; then
    cat "$temp_file"
else
    cat "$temp_file" | xclip -selection clipboard
    if [ "$inverse_mode" = true ]; then
        echo "All lines except $ranges from file '$file' have been copied to the clipboard."
    else
        echo "Lines $ranges from file '$file' have been copied to the clipboard."
    fi
fi

rm "$temp_file"