#!/bin/bash

# Countdown / Alarm Timer
# Usage:
#   countdown.sh [OPTIONS] [minutes]
#   countdown.sh <minutes> [importance] [audiofile]   (legacy mode)
#
# Options:
#   -g, --gui               Launch GUI mode
#   -a, --alarm HH:MM       Alarm mode: fire at a specific clock time
#   -i, --importance LEVEL   low | normal | critical (default: normal)
#   -s, --sound FILE        Path to audio file (overrides importance default)
#   -p, --popup             Show zenity popup notification (auto-enabled in GUI mode)
#   -h, --help              Show usage

# --- Constants & Config ---

if [ ! -d "${HOME}/.config/countdown" ]; then
    echo "Warning: config directory does not exist; exiting"
    exit 1
fi
config_dir="${HOME}/.config/countdown"

# --- Helper Functions ---

show_usage() {
    cat <<'USAGE'
Usage:
  countdown.sh [OPTIONS] [minutes]
  countdown.sh <minutes> [importance] [audiofile]   (legacy)

Options:
  -g, --gui               Launch GUI mode (backgrounds after dialog)
  -a, --alarm HH:MM       Alarm at a specific clock time
  -i, --importance LEVEL   low | normal | critical (default: normal)
  -s, --sound FILE        Custom audio file (overrides importance default)
  -p, --popup             Show zenity popup on completion
  -h, --help              Show this help

Config directory: ~/.config/countdown/
  The script expects this directory to exist. It should contain:
    default_audio.ogg   Audio file for normal importance
    low_audio.ogg       Audio file for low importance
    high_audio.ogg      Audio file for critical importance
    default_icon.png    Notification icon for normal importance
    low_icon.png        Notification icon for low importance
    high_icon.png       Notification icon for critical importance
  Additional audio files (.ogg, .mp3, .wav, .flac) placed here
  will appear as options in the GUI sound picker.
USAGE
}

validate_audiofile() {
    local f="$1"
    if [ ! -f "$f" ]; then
        echo "Error: The file '$f' does not exist."
        return 1
    fi
    local mimetype
    mimetype=$(file --mime-type -b "$f")
    if [[ "$mimetype" != audio/* ]]; then
        echo "Error: '$f' is not a valid audio file. Detected MIME type: $mimetype"
        return 1
    fi
    return 0
}

resolve_importance() {
    local level="$1"
    case "$level" in
        low)
            : "${audiofile:=$config_dir/low_audio.ogg}"
            importance_level="low"
            icon="$config_dir/low_icon.png"
            ;;
        critical)
            : "${audiofile:=$config_dir/high_audio.ogg}"
            importance_level="critical"
            icon="$config_dir/high_icon.png"
            ;;
        normal|*)
            : "${audiofile:=$config_dir/default_audio.ogg}"
            importance_level="normal"
            icon="$config_dir/default_icon.png"
            ;;
    esac

    # Build notification text now that audiofile is known
    local basename_audio
    basename_audio=$(basename "$audiofile")
    if [[ "$importance_level" == "critical" ]]; then
        notification_text="Warning!!
${time_label} elapsed!
Now playing: ${basename_audio}.
If you don't hear it, check your speakers."
    elif [[ "$importance_level" == "low" ]]; then
        notification_text="${time_label} is up."
    else
        notification_text="${time_label} is up!
Now playing: ${basename_audio}.
If you don't hear it, check your speakers."
    fi
}

# Convert HH:MM alarm time to seconds from now
calculate_seconds() {
    local target="$1"
    if ! [[ "$target" =~ ^[0-9]{1,2}:[0-9]{2}$ ]]; then
        echo "Error: Alarm time must be in HH:MM format." >&2
        return 1
    fi

    local target_epoch now_epoch
    target_epoch=$(date -d "today $target" +%s 2>/dev/null)
    if [ $? -ne 0 ]; then
        echo "Error: Invalid time '$target'." >&2
        return 1
    fi
    now_epoch=$(date +%s)

    # If target is in the past, it means tomorrow
    if (( target_epoch <= now_epoch )); then
        target_epoch=$(date -d "tomorrow $target" +%s)
    fi

    echo $(( target_epoch - now_epoch ))
}

run_countdown_cli() {
    local total_seconds=$1
    local remaining=$total_seconds

    # Sleep any partial first minute so we land on whole minutes
    local partial=$(( remaining % 60 ))
    if (( partial > 0 )); then
        sleep "$partial"
        remaining=$(( remaining - partial ))
    fi

    local minutes_left=$(( remaining / 60 ))
    for ((i=minutes_left; i>0; i--)); do
        echo "$(date +'%H:%M'): $i minute(s) remaining"
        sleep 60
    done
}

run_countdown_gui() {
    local total_seconds=$1
    local total_minutes=$(( (total_seconds + 59) / 60 ))

    local remaining=$total_seconds
    local partial=$(( remaining % 60 ))

    (
        if (( partial > 0 )); then
            local mins_left=$(( remaining / 60 + 1 ))
            local pct=$(( (total_minutes - mins_left) * 100 / total_minutes ))
            echo "$pct"
            echo "# ~${mins_left} minute(s) remaining"
            sleep "$partial"
            remaining=$(( remaining - partial ))
        fi

        local minutes_left=$(( remaining / 60 ))
        for ((i=minutes_left; i>0; i--)); do
            local pct=$(( (total_minutes - i) * 100 / total_minutes ))
            echo "$pct"
            echo "# $i minute(s) remaining (until $(date -d "+${i} minutes" +%H:%M))"
            sleep 60
        done
        echo "100"
    ) | zenity --progress --title="Countdown Timer" \
               --text="Starting..." \
               --percentage=0 --auto-close --width=350

    # If user closed the dialog, treat as cancel
    if [ $? -ne 0 ]; then
        echo "Countdown cancelled."
        exit 0
    fi
}

fire_notification() {
    # 1) notify-send
    notify-send -u "$importance_level" -i "$icon" "Timer Complete" "$notification_text"

    # 2) Optional zenity popup (non-blocking, so audio plays simultaneously)
    if [[ "$use_popup" == "true" ]]; then
        local icon_name="dialog-information"
        [[ "$importance_level" == "critical" ]] && icon_name="dialog-warning"

        zenity --info --title="Timer Complete" \
            --text="$notification_text" \
            --icon-name="$icon_name" \
            --width=400 &
    fi

    # 3) Play audio — loop for critical importance
    if [[ "$importance_level" == "critical" ]]; then
        mpv --no-audio-display --loop=3 "$audiofile"
    else
        mpv --no-audio-display "$audiofile"
    fi
}

launch_gui() {
    # Discover sound files in config dir
    local sounds=""
    for f in "$config_dir"/*.ogg "$config_dir"/*.mp3 "$config_dir"/*.wav "$config_dir"/*.flac; do
        [ -f "$f" ] || continue
        local name
        name=$(basename "$f")
        if [ -n "$sounds" ]; then
            sounds="${sounds}|${name}"
        else
            sounds="${name}"
        fi
    done
    sounds="${sounds}|Custom..."

    local result
    result=$(zenity --forms --title="Countdown / Alarm Timer" \
        --text="Set up your timer" \
        --add-combo="Mode" --combo-values="Countdown (minutes)|Alarm (HH:MM)" \
        --add-entry="Time (minutes or HH:MM)" \
        --add-combo="Importance" --combo-values="normal|low|critical" \
        --add-combo="Sound" --combo-values="$sounds" \
        --separator="|" \
        --width=400)

    [ $? -ne 0 ] && exit 0  # user cancelled

    local mode time_val imp sound
    IFS='|' read -r mode time_val imp sound <<< "$result"

    # Defaults
    [ -z "$imp" ] && imp="normal"
    [ -z "$mode" ] && mode="Countdown (minutes)"

    # Handle custom sound
    if [[ "$sound" == "Custom..." ]]; then
        sound=$(zenity --file-selection --title="Select Audio File" \
            --file-filter="Audio files|*.ogg *.mp3 *.wav *.flac *.opus" \
            --file-filter="All files|*")
        [ $? -ne 0 ] && exit 0
        audiofile="$sound"
    elif [ -n "$sound" ]; then
        audiofile="$config_dir/$sound"
    fi

    # Validate time input
    if [ -z "$time_val" ]; then
        zenity --error --text="No time value entered."
        exit 1
    fi

    importance_input="$imp"
    use_popup="true"

    if [[ "$mode" == *"Alarm"* ]]; then
        alarm_time="$time_val"
    else
        if ! [[ "$time_val" =~ ^[0-9]+$ ]]; then
            zenity --error --text="For countdown mode, enter a number of minutes."
            exit 1
        fi
        countdown_minutes="$time_val"
    fi
}

# --- Argument Parsing ---

gui_mode="false"
use_popup="false"
alarm_time=""
countdown_minutes=""
importance_input="normal"
audiofile=""

# Detect legacy positional mode: first arg is a plain integer
if [[ $# -gt 0 && "$1" =~ ^[0-9]+$ && "$1" != "0" ]]; then
    countdown_minutes="$1"
    [ -n "$2" ] && importance_input="$2"
    [ -n "$3" ] && audiofile="$3"
else
    while [[ $# -gt 0 ]]; do
        case "$1" in
            -g|--gui)
                gui_mode="true"
                shift ;;
            -a|--alarm)
                alarm_time="$2"
                shift 2 ;;
            -i|--importance)
                importance_input="$2"
                shift 2 ;;
            -s|--sound)
                audiofile="$2"
                shift 2 ;;
            -p|--popup)
                use_popup="true"
                shift ;;
            -h|--help)
                show_usage
                exit 0 ;;
            *)
                # Maybe a bare number of minutes
                if [[ "$1" =~ ^[0-9]+$ ]]; then
                    countdown_minutes="$1"
                else
                    echo "Unknown option: $1"
                    show_usage
                    exit 1
                fi
                shift ;;
        esac
    done
fi

# --- Main ---

if [[ "$gui_mode" == "true" ]]; then
    launch_gui
fi

run_timer() {
    # Determine total seconds
    local total_seconds=""

    if [ -n "$alarm_time" ]; then
        total_seconds=$(calculate_seconds "$alarm_time")
        [ $? -ne 0 ] && exit 1
        time_label="Alarm for $alarm_time"
        echo "Alarm set for $alarm_time ($(( total_seconds / 60 )) minutes from now)"
    elif [ -n "$countdown_minutes" ]; then
        total_seconds=$(( countdown_minutes * 60 ))
        time_label="${countdown_minutes} minute(s)"
        echo "Countdown: $countdown_minutes minute(s)"
    else
        echo "Error: No time specified."
        show_usage
        exit 1
    fi

    # Resolve importance, icon, audiofile, notification text
    resolve_importance "$importance_input"

    # Validate audio
    if ! validate_audiofile "$audiofile"; then
        exit 1
    fi

    # Run the countdown
    if [[ "$gui_mode" == "true" ]]; then
        run_countdown_gui "$total_seconds"
    else
        run_countdown_cli "$total_seconds"
    fi

    # Fire notification
    fire_notification
}

# In GUI mode, background after the dialog so the terminal is freed
if [[ "$gui_mode" == "true" ]]; then
    run_timer &
    disown
    echo "Timer running in background (PID: $!)"
else
    run_timer
fi
