#!/usr/bin/env bash


# Configuration settings
defaultCity="Raleigh, NC"
defaultLat="35.78"
defaultLon="-78.64"
tempUnit="F"
updateInterval=30

configDir="${XDG_CONFIG_HOME:-$HOME/.config}/stormux/I38"
configFile="$configDir/weather.conf"
mkdir -p "$configDir"

# Initialize variables
cityName="Detecting..."
latitude=0.0
longitude=0.0
currentTemp="--"
currentHumidity="--"
currentWindSpeed="--"
currentWindSpeedMph="--"
currentConditions="Unknown"
weatherLastUpdate=0
severeWeatherAlerted=0

declare -a forecastDates=("--" "--" "--")
declare -a forecastFormattedDates=("--" "--" "--")
declare -a forecastMinTemps=("--" "--" "--")
declare -a forecastMaxTemps=("--" "--" "--")
declare -a forecastConditions=("Unknown" "Unknown" "Unknown")

declare -A weatherCodes
weatherCodes[0]="Clear sky"
weatherCodes[1]="Mainly clear"
weatherCodes[2]="Partly cloudy"
weatherCodes[3]="Overcast"
weatherCodes[45]="Fog"
weatherCodes[48]="Rime fog"
weatherCodes[51]="Light drizzle"
weatherCodes[53]="Moderate drizzle"
weatherCodes[55]="Dense drizzle"
weatherCodes[56]="Light freezing drizzle"
weatherCodes[57]="Dense freezing drizzle"
weatherCodes[61]="Slight rain"
weatherCodes[63]="Moderate rain"
weatherCodes[65]="Heavy rain"
weatherCodes[66]="Light freezing rain"
weatherCodes[67]="Heavy freezing rain"
weatherCodes[71]="Slight snow fall"
weatherCodes[73]="Moderate snow fall"
weatherCodes[75]="Heavy snow fall"
weatherCodes[77]="Snow flurries"
weatherCodes[80]="Slight rain showers"
weatherCodes[81]="Moderate rain showers"
weatherCodes[82]="Heavy rain showers"
weatherCodes[85]="Slight snow showers"
weatherCodes[86]="Heavy snow showers"
weatherCodes[95]="Thunderstorm"
weatherCodes[96]="Thunderstorm with slight hail"
weatherCodes[99]="Thunderstorm with heavy hail"

declare -a severeWeatherCodes=(65 67 75 82 86 95 96 99)

# Button return codes
refreshBtn=0
quitBtn=1
settingsBtn=2

trap "pkill -P $$" EXIT INT TERM

# Load configuration if available
if [ -f "$configFile" ]; then
    source "$configFile"
    # Convert lastWeatherUpdate string to integer if it exists
    [[ -n "$lastWeatherUpdate" ]] && weatherLastUpdate=$lastWeatherUpdate || weatherLastUpdate=0
    
    if [[ -n "$city" ]]; then
        cityName="$city"
        latitude="$latitude"
        longitude="$longitude"
    fi
    
    # Try to reload saved weather data
    if [[ "$weatherLastUpdate" -gt 0 && "$currentTemp" == "--" ]]; then
        [[ -n "$savedCurrentTemp" ]] && currentTemp="$savedCurrentTemp"
        [[ -n "$savedCurrentHumidity" ]] && currentHumidity="$savedCurrentHumidity"
        [[ -n "$savedCurrentConditions" ]] && currentConditions="$savedCurrentConditions"
        [[ -n "$savedCurrentWindSpeed" ]] && currentWindSpeedMph="$savedCurrentWindSpeed"
        
        for i in {0..2}; do
            varDate="savedForecastDate_$i"
            varMin="savedForecastMin_$i"
            varMax="savedForecastMax_$i"
            varCond="savedForecastCond_$i"
            
            [[ -n "${!varDate}" ]] && forecastFormattedDates[$i]="${!varDate}"
            [[ -n "${!varMin}" ]] && forecastMinTemps[$i]="${!varMin}"
            [[ -n "${!varMax}" ]] && forecastMaxTemps[$i]="${!varMax}"
            [[ -n "${!varCond}" ]] && forecastConditions[$i]="${!varCond}"
        done
    fi
fi

# Helper functions
time_diff() {
    local timestamp="$1"
    local now=$(date +%s)
    local diff=$((now - timestamp))
    
    if [ $diff -lt 60 ]; then
        echo "just now"
    elif [ $diff -lt 3600 ]; then
        local minutes=$((diff / 60))
        echo "$minutes minute$([ $minutes -ne 1 ] && echo "s") ago"
    elif [ $diff -lt 86400 ]; then
        local hours=$((diff / 3600))
        echo "$hours hour$([ $hours -ne 1 ] && echo "s") ago"
    else
        local days=$((diff / 86400))
        echo "$days day$([ $days -ne 1 ] && echo "s") ago"
    fi
}

celsius_to_fahrenheit() {
    local celsius="$1"
    [[ -z "$celsius" || "$celsius" == "--" ]] && echo "--" && return
    [[ ! "$celsius" =~ ^-?[0-9]+(\.[0-9]+)?$ ]] && echo "--" && return
    
    local fahrenheit
    fahrenheit=$(echo "scale=1; ($celsius * 9/5) + 32" | bc -l)
    echo "$fahrenheit"
}

kmh_to_mph() {
    local kmh="$1"
    [[ -z "$kmh" || "$kmh" == "--" ]] && echo "--" && return
    [[ ! "$kmh" =~ ^-?[0-9]+(\.[0-9]+)?$ ]] && echo "--" && return
    
    local mph
    mph=$(echo "scale=1; $kmh * 0.621371" | bc -l)
    echo "$mph"
}

format_date() {
    local isoDate="$1"
    [[ -z "$isoDate" || "$isoDate" == "--" ]] && echo "--" && return
    date -d "$isoDate" "+%A, %B %d" 2>/dev/null || echo "$isoDate"
}

# Save configuration
save_config() {
    cat > "$configFile" << EOF
city="$cityName"
latitude="$latitude"
longitude="$longitude"
tempUnit=$tempUnit
updateInterval=$updateInterval
lastWeatherUpdate=$weatherLastUpdate
savedCurrentTemp="$currentTemp"
savedCurrentHumidity="$currentHumidity"
savedCurrentConditions="$currentConditions"
savedCurrentWindSpeed="$currentWindSpeedMph"
savedForecastDate_0="${forecastFormattedDates[0]}"
savedForecastMin_0="${forecastMinTemps[0]}"
savedForecastMax_0="${forecastMaxTemps[0]}"
savedForecastCond_0="${forecastConditions[0]}"
savedForecastDate_1="${forecastFormattedDates[1]}"
savedForecastMin_1="${forecastMinTemps[1]}"
savedForecastMax_1="${forecastMaxTemps[1]}"
savedForecastCond_1="${forecastConditions[1]}"
savedForecastDate_2="${forecastFormattedDates[2]}"
savedForecastMin_2="${forecastMinTemps[2]}"
savedForecastMax_2="${forecastMaxTemps[2]}"
savedForecastCond_2="${forecastConditions[2]}"
EOF
}

# Play severe weather alert sound using Sox
play_severe_weather_alert() {
    if command -v play &>/dev/null; then
        # Generate alert sound pattern using sox
        play -nqV0 synth 2 sine 853 sine 960 remix - norm -15 &
    fi
    
    # Also display notification if available
    if command -v notify-send &>/dev/null; then
        notify-send "Severe Weather Alert" "Severe weather conditions detected for $cityName: $currentConditions" -u critical
    fi
}

# Function to check if a value is in array
in_array() {
    local value="$1"
    shift
    local array=("$@")
    
    for item in "${array[@]}"; do
        if [[ "$item" == "$value" ]]; then
            return 0  # True, found in array
        fi
    done
    return 1  # False, not found
}

# Function to detect location
get_location() {
    # Only try location detection if we don't already have a city name
    if [[ "$cityName" == "Detecting..." ]]; then
        echo "Attempting to detect location via ipinfo.io..."
        
        # Try to fetch location data
        local locationData
        locationData=$(curl -s --connect-timeout 5 "https://ipinfo.io/json" 2>/dev/null)
        
        if [[ $? -eq 0 && -n "$locationData" && $(echo "$locationData" | jq -e '.city') ]]; then
            echo "Location data received successfully"
            cityName=$(echo "$locationData" | jq -r '.city // "Unknown"')
            local region=$(echo "$locationData" | jq -r '.region // ""')
            # Add region/state to city name if available
            [[ -n "$region" ]] && cityName="$cityName, $region"
            
            # Extract coordinates directly from the "loc" field
            local loc=$(echo "$locationData" | jq -r '.loc // "0,0"')
            latitude=$(echo "$loc" | cut -d',' -f1)
            longitude=$(echo "$loc" | cut -d',' -f2)
            save_config
        else
            cityName="$defaultCity"
            latitude="$defaultLat"
            longitude="$defaultLon"
            save_config
        fi
    fi
}

# Function to fetch weather data
fetch_weather_data() {
    local now=$(date +%s)
    local elapsedMinutes=$(( (now - weatherLastUpdate) / 60 ))
    
    # Only fetch if needed
    if [[ $weatherLastUpdate -eq 0 || $elapsedMinutes -ge $updateInterval ]]; then
        local url="https://api.open-meteo.com/v1/forecast?latitude=$latitude&longitude=$longitude&current=temperature_2m,relative_humidity_2m,weather_code,wind_speed_10m&daily=weather_code,temperature_2m_max,temperature_2m_min&timezone=auto"
        local response=$(curl -s --connect-timeout 10 "$url" 2>/dev/null)
        
        if [[ $? -eq 0 && -n "$response" && $(echo "$response" | jq -e '.current' 2>/dev/null) ]]; then
            # Update current weather data
            local tempCelsius=$(echo "$response" | jq -r '.current.temperature_2m // "--"' 2>/dev/null)
            [[ "$tempCelsius" != "--" && "$tempCelsius" != "null" ]] && currentTemp=$(celsius_to_fahrenheit "$tempCelsius") || currentTemp="--"
            
            currentHumidity=$(echo "$response" | jq -r '.current.relative_humidity_2m // "--"' 2>/dev/null)
            [[ "$currentHumidity" == "null" ]] && currentHumidity="--"
            
            currentWindSpeed=$(echo "$response" | jq -r '.current.wind_speed_10m // "--"' 2>/dev/null)
            if [[ "$currentWindSpeed" != "--" && "$currentWindSpeed" != "null" ]]; then
                currentWindSpeedMph=$(kmh_to_mph "$currentWindSpeed")
            else
                currentWindSpeed="--"
                currentWindSpeedMph="--"
            fi
            
            local weatherCode=$(echo "$response" | jq -r '.current.weather_code // 0' 2>/dev/null)
            [[ "$weatherCode" == "null" ]] && weatherCode=0
            currentConditions="${weatherCodes[$weatherCode]:-Unknown}"
            
            # Check for severe weather and play alert if needed
            if in_array "$weatherCode" "${severeWeatherCodes[@]}"; then
                if [ "$severeWeatherAlerted" -eq 0 ]; then
                    play_severe_weather_alert
                    severeWeatherAlerted=1
                fi
            else
                # Reset alert flag if weather is no longer severe
                severeWeatherAlerted=0
            fi
            
            # Process forecast data (limited to 3 days)
            if [[ $(echo "$response" | jq -e '.daily' 2>/dev/null) ]]; then
                for i in {0..2}; do
                    # Process forecast data
                    forecastDates[$i]=$(echo "$response" | jq -r ".daily.time[$i] // \"--\"" 2>/dev/null)
                    [[ "${forecastDates[$i]}" != "--" && "${forecastDates[$i]}" != "null" ]] && \
                        forecastFormattedDates[$i]=$(format_date "${forecastDates[$i]}") || forecastFormattedDates[$i]="--"
                    
                    local minTempC=$(echo "$response" | jq -r ".daily.temperature_2m_min[$i] // \"--\"" 2>/dev/null)
                    [[ "$minTempC" != "--" && "$minTempC" != "null" ]] && \
                        forecastMinTemps[$i]=$(celsius_to_fahrenheit "$minTempC") || forecastMinTemps[$i]="--"
                    
                    local maxTempC=$(echo "$response" | jq -r ".daily.temperature_2m_max[$i] // \"--\"" 2>/dev/null)
                    [[ "$maxTempC" != "--" && "$maxTempC" != "null" ]] && \
                        forecastMaxTemps[$i]=$(celsius_to_fahrenheit "$maxTempC") || forecastMaxTemps[$i]="--"
                    
                    local code=$(echo "$response" | jq -r ".daily.weather_code[$i] // 0" 2>/dev/null)
                    [[ "$code" == "null" ]] && code=0
                    forecastConditions[$i]="${weatherCodes[$code]:-Unknown}"
                done
            fi
            
            # Update timestamp
            weatherLastUpdate=$(date +%s)
            save_config
        else
            echo "Failed to fetch weather data. Response code: $?"
            if [[ -n "$response" ]]; then
                echo "First 100 chars of response: ${response:0:100}"
            fi
        fi
    fi
}

# Function to change location (for settings)
change_location() {
    local newLocation="$1"
    
    if [[ -n "$newLocation" && "$newLocation" != "$cityName" ]]; then
        # Try to parse the location using curl to a geocoding service
        local result=$(curl -s --connect-timeout 10 "https://nominatim.openstreetmap.org/search?q=$newLocation&format=json" 2>/dev/null)
        
        if [[ -n "$result" && $(echo "$result" | jq -e '.[0]') ]]; then
            cityName="$newLocation"
            latitude=$(echo "$result" | jq -r '.[0].lat // "0.0"')
            longitude=$(echo "$result" | jq -r '.[0].lon // "0.0"')
            
            # Force weather update
            weatherLastUpdate=0
            save_config
            return 0
        else
            yad --title "Location Error" --text="Could not find location: $newLocation" --button=gtk-ok
            return 1
        fi
    fi
    return 1
}

# Display weather information in a text-info dialog
display_weather() {
    local lastUpdateText="Never updated"
    [[ "$weatherLastUpdate" -gt 0 ]] && lastUpdateText="Last updated: $(time_diff "$weatherLastUpdate")"
    
    # Create the weather information text with proper line breaks
    weatherInfoText="Weather for $cityName
$lastUpdateText

Current Conditions
Temperature: ${currentTemp}° F
Conditions: $currentConditions
Humidity: ${currentHumidity}%
Wind Speed: ${currentWindSpeedMph} mph

3-Day Forecast
────────────────────────────────────
${forecastFormattedDates[0]}
Temp: ${forecastMinTemps[0]}° to ${forecastMaxTemps[0]}° F
Conditions: ${forecastConditions[0]}
────────────────────────────────────
${forecastFormattedDates[1]}
Temp: ${forecastMinTemps[1]}° to ${forecastMaxTemps[1]}° F
Conditions: ${forecastConditions[1]}
────────────────────────────────────
${forecastFormattedDates[2]}
Temp: ${forecastMinTemps[2]}° to ${forecastMaxTemps[2]}° F
Conditions: ${forecastConditions[2]}

End of text. Press Control+Home to return to the beginning."

    # Display in text-info dialog for screen reader accessibility
    echo "$weatherInfoText" | yad --pname=I38Weather \
        --title="I38 Weather Monitor" \
        --text-info \
        --show-cursor \
        --width=500 \
        --height=600 \
        --center \
        --button="Settings:$settingsBtn" \
        --button="Refresh:$refreshBtn" \
        --button="Close:$quitBtn"
    
    return $?
}

# Function to display settings dialog
display_settings() {
    local ret=$(yad --pname=I38WeatherSettings \
        --title="I38 Weather Settings" \
        --form \
        --width=400 \
        --center \
        --field="Location:":TEXT "$cityName" \
        --field="Current Coordinates:":LBL "Lat: $latitude, Lon: $longitude" \
        --field="Temperature Unit:":CB "F!C" \
        --field="Update Interval (minutes):":NUM "$updateInterval!5..120!5" \
        --button="Cancel:1" \
        --button="Save:0")
    
    local saveResult=$?
    
    if [[ $saveResult -eq 0 && -n "$ret" ]]; then
        local newLocation=$(echo "$ret" | cut -d"|" -f1)
        local newUnit=$(echo "$ret" | cut -d"|" -f3)
        local newInterval=$(echo "$ret" | cut -d"|" -f4)
        
        # Apply any changes
        [[ -n "$newLocation" && "$newLocation" != "$cityName" ]] && change_location "$newLocation"
        [[ -n "$newUnit" && "$newUnit" != "$tempUnit" ]] && tempUnit="$newUnit" && save_config
        [[ -n "$newInterval" && "$newInterval" != "$updateInterval" ]] && updateInterval="$newInterval" && save_config
    fi
}

# Main loop
while : ; do
    get_location
    fetch_weather_data
    
    # Display weather using the text-info widget
    display_weather
    ret=$?
    
    # Handle button actions
    case $ret in
        $refreshBtn)
            # Force a weather update
            weatherLastUpdate=0
            continue
            ;;
        $settingsBtn)
            # Display settings dialog
            display_settings
            continue
            ;;
        $quitBtn|252)
            # Quit button or window closed
            break
            ;;
    esac
done

exit 0
