#!/usr/bin/env bash

# Initialize variables for spd-say options
rate=""
pitch=""
pitch_range=""
punctuation_mode=""
wait_flag=""
ssml_mode=""
application_name="espeak-ng-wrapper"

# Function to check if a string is numeric
is_numeric() {
    [[ "$1" =~ ^-?[0-9]+$ ]]
}

# Process arguments
while [[ $# -gt 0 ]]; do
    case "$1" in
        # Handle speed parameter (can be -s 100 or -s100)
        -s*)
            if [[ "$1" == "-s" && -n "$2" && $(is_numeric "$2") ]]; then
                # Format: -s 100
                espeak_speed="$2"
                shift 2
            elif [[ "$1" =~ ^-s([0-9]+)$ ]]; then
                # Format: -s100
                espeak_speed="${BASH_REMATCH[1]}"
                shift
            else
                # Invalid format, skip
                shift
                continue
            fi
            
            # Convert espeak-ng speed to spd-say rate
            spd_rate=$(( (($espeak_speed - 175) * 200) / 420 ))
            
            # Clamp to spd-say's allowed range
            if (( spd_rate > 100 )); then
                spd_rate=100
            elif (( spd_rate < -100 )); then
                spd_rate=-100
            fi
            rate="-r $spd_rate"
            ;;
            
        # Handle pitch parameter (can be -p 50 or -p50)
        -p*)
            if [[ "$1" == "-p" && -n "$2" && $(is_numeric "$2") ]]; then
                # Format: -p 50
                espeak_pitch="$2"
                shift 2
            elif [[ "$1" =~ ^-p([0-9]+)$ ]]; then
                # Format: -p50
                espeak_pitch="${BASH_REMATCH[1]}"
                shift
            else
                # Invalid format, skip
                shift
                continue
            fi
            
            # Convert espeak-ng pitch to spd-say pitch
            spd_pitch=$(( (($espeak_pitch - 50) * 200) / 99 ))
            
            # Clamp to spd-say's allowed range
            if (( spd_pitch > 100 )); then
                spd_pitch=100
            elif (( spd_pitch < -100 )); then
                spd_pitch=-100
            fi
            pitch="-p $spd_pitch"
            ;;
            
        # Handle pitch range parameter (can be -P 50 or -P50)
        -P*)
            if [[ "$1" == "-P" && -n "$2" && $(is_numeric "$2") ]]; then
                # Format: -P 50
                espeak_pitch_range="$2"
                shift 2
            elif [[ "$1" =~ ^-P([0-9]+)$ ]]; then
                # Format: -P50
                espeak_pitch_range="${BASH_REMATCH[1]}"
                shift
            else
                # Invalid format, skip
                shift
                continue
            fi
            
            # Convert espeak-ng pitch range to spd-say pitch range
            spd_pitch_range=$(( (($espeak_pitch_range - 50) * 200) / 99 ))
            
            # Clamp to spd-say's allowed range
            if (( spd_pitch_range > 100 )); then
                spd_pitch_range=100
            elif (( spd_pitch_range < -100 )); then
                spd_pitch_range=-100
            fi
            pitch_range="-R $spd_pitch_range"
            ;;
            
        # Handle punctuation mode parameter (can be -m none or -mnone)
        -m*)
            if [[ "$1" == "-m" && -n "$2" ]]; then
                # Format: -m none
                punct_mode="$2"
                shift 2
            elif [[ "$1" =~ ^-m(.+)$ ]]; then
                # Format: -mnone
                punct_mode="${BASH_REMATCH[1]}"
                shift
            else
                # Invalid format, skip
                shift
                continue
            fi
            
            # Process the mode
            if [[ "$punct_mode" == "ssml" ]]; then
                # SSML mode for spd-say
                ssml_mode="-x"
            else
                # Map to punctuation mode if specified
                case "$punct_mode" in
                    none|some|most|all)
                        punctuation_mode="-m $punct_mode"
                        ;;
                esac
            fi
            ;;
            
        # File input parameter (can be -f file.txt or -ffile.txt)
        -f*)
            if [[ "$1" == "-f" && -n "$2" ]]; then
                # Format: -f file.txt
                input_file="$2"
                shift 2
            elif [[ "$1" =~ ^-f(.+)$ ]]; then
                # Format: -ffile.txt
                input_file="${BASH_REMATCH[1]}"
                shift
            else
                # Invalid format, skip
                shift
                continue
            fi
            
            # Check if file exists
            if [[ -f "$input_file" ]]; then
                input_from_file="$input_file"
            fi
            ;;
            
        # Wait until speaking is done
        -z)
            wait_flag="-w"
            shift
            ;;
            
        # Input from stdin
        --stdin)
            input_from_stdin=1
            shift
            ;;
            
        # Silently discard voice, volume, and other unsupported options with possibly attached values
        -v*|-a*|-l*|-d*|-g*|-k*|-b*|-w*|-q*|-x*|-X*|-D*|--compile*|--ipa|--path|--pho|--phonout|--punct*|--sep*|--split*|--stdout|--tie*|--version|--voices*|--load*)
            # Skip the option (and its separated value if it exists)
            if [[ "$1" =~ ^-[a-zA-Z]$ && -n "$2" && ! "$2" =~ ^- ]]; then
                # Format with separate value: -v en-us
                shift 2
            else
                # Format with attached value or no value: -ven-us or just -q
                shift
            fi
            ;;
            
        # Any other unrecognized options - silently discard
        -*)
            # Skip the option (and its separated value if it exists)
            if [[ "$1" =~ ^-[a-zA-Z]$ && -n "$2" && ! "$2" =~ ^- ]]; then
                # Format with separate value
                shift 2
            else
                # Format with attached value or no value
                shift
            fi
            ;;
            
        # Text to speak - anything not starting with -
        *)
            # Collect all non-option arguments as text to speak
            if [[ -z "$text" ]]; then
                text="$1"
            else
                text="$text $1"
            fi
            shift
            ;;
    esac
done

# Build the spd-say command with only the supported converted options
spd_cmd="spd-say $rate $pitch $pitch_range $punctuation_mode $ssml_mode $wait_flag -N $application_name"

# Handle the input based on what was provided
if [[ -n "$input_from_file" ]]; then
    # Input from specified file
    spd_cmd="$spd_cmd -e --"
    cat "$input_from_file" | $spd_cmd
elif [[ -n "$input_from_stdin" ]]; then
    # Input from stdin all at once
    spd_cmd="$spd_cmd -e --"
    cat | $spd_cmd
elif [[ -n "$text" ]]; then
    # Text provided as arguments
    $spd_cmd -- "$text"
else
    # No text provided, read from stdin line by line
    spd_cmd="$spd_cmd -e --"
    cat | $spd_cmd
fi

# Exit with success
exit 0
