#!/usr/bin/env bash
###############################################################################
# dtime — World clock via dmenu + dunst
#
# Maintainer:   Kris Yotam <krisyotam@pm.me>
# License:      MIT
# Created:      2026-02-15
#
# Select a city/region from presets or type any city name.
# Displays the current time there via dunst notification.
###############################################################################

# Preset cities → IANA timezone
declare -A PRESETS=(
    ["New York"]="America/New_York"
    ["Los Angeles"]="America/Los_Angeles"
    ["Chicago"]="America/Chicago"
    ["London"]="Europe/London"
    ["Paris"]="Europe/Paris"
    ["Berlin"]="Europe/Berlin"
    ["Tokyo"]="Asia/Tokyo"
    ["Seoul"]="Asia/Seoul"
    ["Shanghai"]="Asia/Shanghai"
    ["Hong Kong"]="Asia/Hong_Kong"
    ["Dubai"]="Asia/Dubai"
    ["Mumbai"]="Asia/Kolkata"
    ["Sydney"]="Australia/Sydney"
    ["Auckland"]="Pacific/Auckland"
    ["Moscow"]="Europe/Moscow"
    ["Istanbul"]="Europe/Istanbul"
    ["Cairo"]="Africa/Cairo"
    ["São Paulo"]="America/Sao_Paulo"
    ["Mexico City"]="America/Mexico_City"
    ["Toronto"]="America/Toronto"
    ["Singapore"]="Asia/Singapore"
    ["Bangkok"]="Asia/Bangkok"
    ["Jakarta"]="Asia/Jakarta"
    ["Nairobi"]="Africa/Nairobi"
    ["Lagos"]="Africa/Lagos"
    ["Reykjavik"]="Atlantic/Reykjavik"
    ["Honolulu"]="Pacific/Honolulu"
    ["Anchorage"]="America/Anchorage"
    ["Denver"]="America/Denver"
    ["UTC"]="UTC"
)

# Display order
ORDERED=(
    "New York" "Los Angeles" "Chicago" "Toronto" "Mexico City"
    "São Paulo" "London" "Paris" "Berlin" "Moscow" "Istanbul"
    "Cairo" "Nairobi" "Lagos" "Dubai" "Mumbai" "Bangkok"
    "Jakarta" "Singapore" "Shanghai" "Hong Kong" "Seoul" "Tokyo"
    "Sydney" "Auckland" "Reykjavik" "Honolulu" "Anchorage" "Denver" "UTC"
)

###############################################################################
# resolve a free-form city name to a timezone
###############################################################################

resolve_tz() {
    local query="$1"

    # Check presets first (case-insensitive)
    for city in "${!PRESETS[@]}"; do
        if [[ "${city,,}" == "${query,,}" ]]; then
            echo "${PRESETS[$city]}"
            return 0
        fi
    done

    # Search IANA timezone database for a match
    local match
    match=$(timedatectl list-timezones | grep -i "${query// /_}" | head -1)
    if [ -n "$match" ]; then
        echo "$match"
        return 0
    fi

    # Try partial match on city component (after /)
    match=$(timedatectl list-timezones | grep -i "/${query// /_}" | head -1)
    if [ -n "$match" ]; then
        echo "$match"
        return 0
    fi

    # Try fuzzy: match anywhere in the tz string
    match=$(timedatectl list-timezones | grep -i "${query// /.*}" | head -1)
    if [ -n "$match" ]; then
        echo "$match"
        return 0
    fi

    return 1
}

###############################################################################
# format and notify
###############################################################################

show_time() {
    local city="$1"
    local tz="$2"

    local time_str offset_str
    time_str=$(TZ="$tz" date '+%I:%M %p')
    offset_str=$(TZ="$tz" date '+%Z (UTC%:z)')
    local day_str
    day_str=$(TZ="$tz" date '+%A, %B %d')
    local local_time
    local_time=$(date '+%I:%M %p')

    notify-send -t 8000 "󰥔  $city" "$time_str\n$day_str\n$offset_str\n\nLocal: $local_time"
}

###############################################################################
# main
###############################################################################

# Build menu
MENU=""
for city in "${ORDERED[@]}"; do
    tz="${PRESETS[$city]}"
    t=$(TZ="$tz" date '+%H:%M')
    MENU+="󰥔  $city  ($t)"$'\n'
done

CHOICE=$(printf '%s' "$MENU" | sed '/^$/d' | dmenu -i -l 20 -p "󰥔  World Clock")
[ -z "$CHOICE" ] && exit 0

# Extract city name (strip icon and time)
CITY=$(echo "$CHOICE" | sed 's/^[^ ]* *//; s/ *([0-9:]*) *$//')

# Try preset first
TZ_FOUND="${PRESETS[$CITY]}"

if [ -z "$TZ_FOUND" ]; then
    # User typed a custom city — resolve it
    TZ_FOUND=$(resolve_tz "$CITY")
    if [ -z "$TZ_FOUND" ]; then
        notify-send -t 5000 "󰥔  dtime" "Could not find timezone for: $CITY"
        exit 1
    fi
fi

show_time "$CITY" "$TZ_FOUND"
