#!/usr/bin/env bash

# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars 
#
# Copyright (C) 2025 Johannes Kamprad
#
# SPDX-License-Identifier: GPL-3.0-or-later


# openweater - OpenWeatherMap Weather Fetcher for Waybar/Status Bars
# Secure API key handling with configurable locations
# including setup script and help
# Options:
#    -h, --help              Show this help message
#    -c, --city-id ID        Override city ID (required if not in config)
#    -k, --api-key KEY       Override API key (not recommended, use config file)
#    -u, --units UNITS       Units: metric, imperial, kelvin (default: $DEFAULT_UNITS)
#    -f, --force-refresh     Force refresh (ignore cache)
#    --setup                 Interactive setup wizard
#    --show-config           Show current configuration

set -euo pipefail

# Set C locale to avoid German decimal formatting issues
export LC_NUMERIC=C
export LC_ALL=C

# Colors for output
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

# Default configuration (no default location)
DEFAULT_UNITS="metric"
CONFIG_DIR="${XDG_CONFIG_HOME:-$HOME/.config}"
CONFIG_FILE="$CONFIG_DIR/openweather/config"
CACHE_DIR="${XDG_CACHE_HOME:-$HOME/.cache}/openweather"
CACHE_FILE="$CACHE_DIR/weather_data"
CACHE_DURATION=600  # 10 minutes

# Logging functions
log_error() {
    echo -e "${RED}[ERROR]${NC} $*" >&2
}

log_warn() {
    echo -e "${YELLOW}[WARN]${NC} $*" >&2
}

# Show help
show_help() {
    cat << EOF
Usage: $(basename "$0") [OPTIONS]

Secure OpenWeatherMap weather fetcher with configurable locations.

Options:
    -h, --help              Show this help message
    -c, --city-id ID        Override city ID (required if not in config)
    -k, --api-key KEY       Override API key (not recommended, use config file)
    -u, --units UNITS       Units: metric, imperial, kelvin (default: $DEFAULT_UNITS)
    -f, --force-refresh     Force refresh (ignore cache)
    --setup                 Interactive setup wizard
    --show-config           Show current configuration
    
Configuration:
    Config file: $CONFIG_FILE
    
    Create config file with:
    OPENWEATHER_API_KEY="your_api_key_here"
    OPENWEATHER_CITY_ID="your_city_id"  # Required
    OPENWEATHER_UNITS="metric"          # Optional
    
Examples:
    $(basename "$0")                    # Use config file settings
    $(basename "$0") --city-id 5128581   # New York
    $(basename "$0") --units imperial    # Fahrenheit
    $(basename "$0") --setup             # Run setup wizard
    
Get your free API key at: https://openweathermap.org/api
Find city IDs at: https://openweathermap.org/find
    
EOF
}

# Check dependencies
check_dependencies() {
    local missing_deps=()
    
    for cmd in jq curl; do
        if ! command -v "$cmd" >/dev/null 2>&1; then
            missing_deps+=("$cmd")
        fi
    done
    
    if [[ ${#missing_deps[@]} -gt 0 ]]; then
        log_error "Missing required dependencies: ${missing_deps[*]}"
        echo "Install with: sudo pacman -S ${missing_deps[*]}"
        exit 1
    fi
}

# Load configuration
load_config() {
    # Set defaults (no default city ID)
    OPENWEATHER_CITY_ID=""
    OPENWEATHER_UNITS="$DEFAULT_UNITS"
    
    # Load from config file if it exists
    if [[ -f "$CONFIG_FILE" ]]; then
        source "$CONFIG_FILE"
    fi
    
    # Override with environment variables if set
    OPENWEATHER_API_KEY="${OPENWEATHER_API_KEY:-}"
    OPENWEATHER_CITY_ID="${OPENWEATHER_CITY_ID:-}"
    OPENWEATHER_UNITS="${OPENWEATHER_UNITS:-$DEFAULT_UNITS}"
}

# Validate API key
validate_api_key() {
    if [[ -z "$OPENWEATHER_API_KEY" ]]; then
        log_error "No API key found!"
        echo
        echo "To fix this:"
        echo "1. Get free API key: https://openweathermap.org/api"
        echo "2. Run setup wizard: $0 --setup"
        echo "3. Or set environment variable: export OPENWEATHER_API_KEY=your_key"
        echo "4. Or create config file: $CONFIG_FILE"
        exit 1
    fi
    
    # Basic validation (OpenWeatherMap keys are typically 32 chars)
    if [[ ${#OPENWEATHER_API_KEY} -ne 32 ]]; then
        log_warn "API key length seems incorrect (expected 32 characters, got ${#OPENWEATHER_API_KEY})"
    fi
}

# Validate city ID
validate_city_id() {
    if [[ -z "$OPENWEATHER_CITY_ID" ]]; then
        log_error "No city ID found!"
        echo
        echo "To fix this:"
        echo "1. Run setup wizard: $0 --setup"
        echo "2. Or set environment variable: export OPENWEATHER_CITY_ID=your_city_id"
        echo "3. Or add OPENWEATHER_CITY_ID=\"your_city_id\" to: $CONFIG_FILE"
        echo "4. Or provide city ID via command line: $0 --city-id your_city_id"
        echo
        echo "Find city IDs at: https://openweathermap.org/find"
        exit 1
    fi
    
    # Basic validation (city IDs are typically numeric)
    if [[ ! "$OPENWEATHER_CITY_ID" =~ ^[0-9]+$ ]]; then
        log_warn "City ID format seems incorrect (expected numeric, got: $OPENWEATHER_CITY_ID)"
    fi
}

# Setup wizard
run_setup() {
    echo -e "${GREEN}=== OpenWeatherMap Setup Wizard ===${NC}"
    echo
    
    # Create config directory
    mkdir -p "$(dirname "$CONFIG_FILE")"
    
    # Get API key
    echo "Get your free API key at: https://openweathermap.org/api"
    echo
    echo -n "Enter your OpenWeatherMap API key: "
    read -r api_key
    
    if [[ -z "$api_key" ]]; then
        log_error "API key cannot be empty"
        exit 1
    fi
    
    # Get city ID (required)
    echo
    echo "Find your city ID at: https://openweathermap.org/find"
    echo -n "Enter city ID: "
    read -r city_id
    
    if [[ -z "$city_id" ]]; then
        log_error "City ID cannot be empty"
        exit 1
    fi
    
    # Get units (optional)
    echo
    echo "Available units: metric (°C), imperial (°F), kelvin (K)"
    echo -n "Enter units [metric]: "
    read -r units
    units="${units:-metric}"
    
    # Write config file
    cat > "$CONFIG_FILE" << EOF
# OpenWeatherMap Configuration
# Generated by $(basename "$0") setup wizard on $(date)

# Your API key from https://openweathermap.org/api
OPENWEATHER_API_KEY="$api_key"

# City ID from https://openweathermap.org/find
OPENWEATHER_CITY_ID="$city_id"

# Units: metric, imperial, kelvin
OPENWEATHER_UNITS="$units"
EOF

    # Set secure permissions
    chmod 600 "$CONFIG_FILE"
    
    echo
    echo -e "${GREEN}✅ Configuration saved to: $CONFIG_FILE${NC}"
    echo -e "${GREEN}✅ File permissions set to 600 (user read/write only)${NC}"
    echo
    echo "Testing configuration..."
    
    # Test the configuration
    OPENWEATHER_API_KEY="$api_key"
    OPENWEATHER_CITY_ID="$city_id"
    OPENWEATHER_UNITS="$units"
    
    if fetch_weather_data; then
        echo -e "${GREEN}✅ Configuration test successful!${NC}"
    else
        log_error "Configuration test failed. Please check your API key and city ID."
        exit 1
    fi
}

# Show current configuration
show_config() {
    echo "=== Current Configuration ==="
    echo "Config file: $CONFIG_FILE"
    echo "Cache file: $CACHE_FILE"
    echo "Cache duration: ${CACHE_DURATION}s"
    echo
    
    if [[ -f "$CONFIG_FILE" ]]; then
        echo "Configuration:"
        echo "  API Key: ${OPENWEATHER_API_KEY:0:8}... (${#OPENWEATHER_API_KEY} chars)"
        echo "  City ID: $OPENWEATHER_CITY_ID"
        echo "  Units: $OPENWEATHER_UNITS"
    else
        echo "❌ No configuration file found at: $CONFIG_FILE"
        echo "Run: $0 --setup"
    fi
}

# Check cache validity
is_cache_valid() {
    [[ -f "$CACHE_FILE" ]] && \
    [[ $(($(date +%s) - $(stat -c %Y "$CACHE_FILE" 2>/dev/null || echo 0))) -lt $CACHE_DURATION ]]
}

# Fetch weather data from API
fetch_weather_data() {
    local url="https://api.openweathermap.org/data/2.5/weather?id=${OPENWEATHER_CITY_ID}&units=${OPENWEATHER_UNITS}&appid=${OPENWEATHER_API_KEY}"
    
    local response
    if ! response=$(curl -sf "$url" 2>/dev/null); then
        log_error "Failed to fetch weather data from API"
        return 1
    fi
    
    # Validate JSON response
    if ! echo "$response" | jq . >/dev/null 2>&1; then
        log_error "Invalid JSON response from API"
        return 1
    fi
    
    # Check for API error
    local api_code
    api_code=$(echo "$response" | jq -r '.cod // empty')
    if [[ "$api_code" != "200" ]]; then
        local api_message
        api_message=$(echo "$response" | jq -r '.message // "Unknown API error"')
        log_error "API Error ($api_code): $api_message"
        return 1
    fi
    
    # Cache the response
    mkdir -p "$CACHE_DIR"
    echo "$response" > "$CACHE_FILE"
    
    return 0
}

# Get weather data (from cache or API)
get_weather_data() {
    local force_refresh="${1:-false}"
    
    if [[ "$force_refresh" != "true" ]] && is_cache_valid; then
        cat "$CACHE_FILE"
    else
        if fetch_weather_data; then
            cat "$CACHE_FILE"
        else
            # Fallback to cache if available
            if [[ -f "$CACHE_FILE" ]]; then
                log_warn "Using stale cache data due to API failure"
                cat "$CACHE_FILE"
            else
                return 1
            fi
        fi
    fi
}

# Calculate wind direction
get_wind_direction() {
    local degrees="$1"
    local directions=(N NNE NE ENE E ESE SE SSE S SSW SW WSW W WNW NW NNW)
    local index
    index=$(awk "BEGIN {print int(($degrees % 360) / 22.5)}")
    echo "${directions[$index]}"
}

# Get weather icon
get_weather_icon() {
    local condition="$1"
    case "$condition" in
        'Clear')        echo "☀" ;;  # Clear sky
        'Clouds')       echo "☁" ;;  # Cloudy
        'Rain'|'Drizzle') echo "🌧" ;;  # Rain
        'Snow')         echo "❄" ;;  # Snow
        'Thunderstorm') echo "⛈" ;;  # Thunder
        'Mist'|'Fog')   echo "🌫" ;;  # Fog
        *)              echo "🌤" ;;  # Default
    esac
}

# Safe number formatting (handles locale issues)
safe_printf() {
    local format="$1"
    local number="$2"
    
    # Validate number is actually numeric
    if [[ ! "$number" =~ ^-?[0-9]+(\.[0-9]+)?$ ]]; then
        echo "0.0"
        return 1
    fi
    
    # Use awk for reliable formatting regardless of locale
    awk "BEGIN {printf \"$format\", $number}"
}

# Format weather output
format_weather() {
    local weather_data="$1"
    
    # Parse weather data with error checking
    local condition temp wind_speed_ms wind_deg
    condition=$(echo "$weather_data" | jq -r '.weather[0].main // "Unknown"')
    temp=$(echo "$weather_data" | jq -r '.main.temp // "0"')
    wind_speed_ms=$(echo "$weather_data" | jq -r '.wind.speed // "0"')
    wind_deg=$(echo "$weather_data" | jq -r '.wind.deg // "0"')
    
    # Validate parsed data
    [[ "$condition" == "null" ]] && condition="Unknown"
    [[ "$temp" == "null" ]] && temp="0"
    [[ "$wind_speed_ms" == "null" ]] && wind_speed_ms="0"
    [[ "$wind_deg" == "null" ]] && wind_deg="0"
    
    # Format temperature with safe formatting
    local temp_formatted
    temp_formatted=$(safe_printf "%.1f" "$temp")
    
    # Convert wind speed to km/h with safe formatting
    local wind_speed_kmh
    wind_speed_kmh=$(awk "BEGIN {printf \"%.1f\", ($wind_speed_ms + 0) * 3.6}")
    
    # Get wind direction
    local wind_dir
    wind_dir=$(get_wind_direction "$wind_deg")
    
    # Get weather icon
    local icon
    icon=$(get_weather_icon "$condition")
    
    # Format unit symbol
    local unit_symbol
    case "$OPENWEATHER_UNITS" in
        "imperial") unit_symbol="°F" ;;
        "kelvin")   unit_symbol="K" ;;
        *)          unit_symbol="°C" ;;
    esac
    
    # Output formatted weather
    echo "${icon} ${temp_formatted}${unit_symbol}, ${wind_speed_kmh} km/h ${wind_dir}"
}

# Main function
main() {
    local city_id_override=""
    local api_key_override=""
    local units_override=""
    local force_refresh="false"
    
    # Parse command line arguments
    while [[ $# -gt 0 ]]; do
        case $1 in
            -h|--help)
                show_help
                exit 0
                ;;
            -c|--city-id)
                city_id_override="$2"
                shift 2
                ;;
            -k|--api-key)
                api_key_override="$2"
                shift 2
                ;;
            -u|--units)
                units_override="$2"
                shift 2
                ;;
            -f|--force-refresh)
                force_refresh="true"
                shift
                ;;
            --setup)
                check_dependencies
                run_setup
                exit 0
                ;;
            --show-config)
                load_config
                show_config
                exit 0
                ;;
            *)
                log_error "Unknown option: $1"
                show_help
                exit 1
                ;;
        esac
    done
    
    # Check dependencies
    check_dependencies
    
    # Load configuration
    load_config
    
    # Apply overrides
    [[ -n "$city_id_override" ]] && OPENWEATHER_CITY_ID="$city_id_override"
    [[ -n "$api_key_override" ]] && OPENWEATHER_API_KEY="$api_key_override"
    [[ -n "$units_override" ]] && OPENWEATHER_UNITS="$units_override"
    
    # Validate configuration
    validate_api_key
    validate_city_id
    
    # Get and format weather data
    local weather_data
    if weather_data=$(get_weather_data "$force_refresh"); then
        format_weather "$weather_data"
    else
        echo "⚠️ Weather data unavailable"
        exit 1
    fi
}

# Run main function
main "$@"
