{
  config,
  lib,
  pkgs,
  namespace,
  ...
}:
let
  cfg = config.${namespace}.programs.waybar;

  waybar-weather = pkgs.writeScriptBin "waybar-weather" ''
    #!/usr/bin/env nix-shell
    #! nix-shell -i python3 --pure
    #! nix-shell -p python3 python3Packages.requests

    import os
    import json
    import shutil
    from datetime import datetime, timedelta
    import argparse
    import math

    import requests

    parser = argparse.ArgumentParser(prog='waybar-weather')
    parser.add_argument('--waybar', action='store_true')
    parser.add_argument('--hyprlock', action='store_true')
    args = parser.parse_args()

    # --- MAPPINGS ---

    WWO_CODE = {
        "113": "Sunny",
        "116": "PartlyCloudy",
        "119": "Cloudy",
        "122": "VeryCloudy",
        "143": "Fog",
        "176": "LightShowers",
        "179": "LightSleetShowers",
        "182": "LightSleet",
        "185": "LightSleet",
        "200": "ThunderyShowers",
        "227": "LightSnow",
        "230": "HeavySnow",
        "248": "Fog",
        "260": "Fog",
        "263": "LightShowers",
        "266": "LightRain",
        "281": "LightSleet",
        "284": "LightSleet",
        "293": "LightRain",
        "296": "LightRain",
        "299": "HeavyShowers",
        "302": "HeavyRain",
        "305": "HeavyShowers",
        "308": "HeavyRain",
        "311": "LightSleet",
        "314": "LightSleet",
        "317": "LightSleet",
        "320": "LightSnow",
        "323": "LightSnowShowers",
        "326": "LightSnowShowers",
        "329": "HeavySnow",
        "332": "HeavySnow",
        "335": "HeavySnowShowers",
        "338": "HeavySnow",
        "350": "LightSleet",
        "353": "LightShowers",
        "356": "HeavyShowers",
        "359": "HeavyRain",
        "362": "LightSleetShowers",
        "365": "LightSleetShowers",
        "368": "LightSnowShowers",
        "371": "HeavySnowShowers",
        "374": "LightSleetShowers",
        "377": "LightSleet",
        "386": "ThunderyShowers",
        "389": "ThunderyHeavyRain",
        "392": "ThunderySnowShowers",
        "395": "HeavySnowShowers",
    }

    # Maps WMO codes (OpenMeteo) to WWO codes (wttr.in)
    WMO_TO_WWO = {
        0: "113",  # Clear sky -> Sunny
        1: "113",  # Mainly clear -> Sunny
        2: "116",  # Partly cloudy
        3: "122",  # Overcast -> VeryCloudy
        45: "143", # Fog
        48: "248", # Depositing rime fog
        51: "266", # Drizzle: Light
        53: "266", # Drizzle: Moderate (mapped to LightRain)
        55: "296", # Drizzle: Dense intensity (LightRain usually suits better than heavy)
        56: "281", # Freezing Drizzle: Light
        57: "284", # Freezing Drizzle: Dense
        61: "296", # Rain: Slight
        63: "302", # Rain: Moderate
        65: "308", # Rain: Heavy
        66: "311", # Freezing Rain: Light
        67: "314", # Freezing Rain: Heavy
        71: "326", # Snow fall: Slight
        73: "332", # Snow fall: Moderate
        75: "338", # Snow fall: Heavy
        77: "350", # Snow grains
        80: "353", # Rain showers: Slight
        81: "356", # Rain showers: Moderate
        82: "359", # Rain showers: Violent
        85: "368", # Snow showers: Slight
        86: "371", # Snow showers: Heavy
        95: "386", # Thunderstorm: Slight or moderate
        96: "389", # Thunderstorm with slight hail
        99: "395", # Thunderstorm with heavy hail
    }

    WEATHER_SYMBOL = {
        "Unknown":             "",
        "Cloudy":              "",
        "Fog":                 "",
        "HeavyRain":           "",
        "HeavyShowers":        "",
        "HeavySnow":           "",
        "HeavySnowShowers":    "",
        "LightRain":           "",
        "LightShowers":        "",
        "LightSleet":          "",
        "LightSleetShowers":   "",
        "LightSnow":           "",
        "LightSnowShowers":    "",
        "PartlyCloudy":        "󰖕",
        "Sunny":               "",
        "ThunderyHeavyRain":   "",
        "ThunderyShowers":     "",
        "ThunderySnowShowers": "",
        "VeryCloudy": "",
    }

    WEATHER_CODES = {key: WEATHER_SYMBOL[value] for key, value in WWO_CODE.items()}

    WIND_DIRECTION = {
        "S": "↓", 
        "SW": "↙",
        "SSW": "↙",
        "W": "←", 
        "NW": "↖", 
        "NNW": "↖", 
        "N": "↑", 
        "NE": "↗", 
        "NNE": "↗", 
        "E": "→", 
        "SE": "↘",
        "SSE": "↘",
    }

    WEATHER_SYMBOL_WI_DAY = {
        "Unknown":             "",
        "Cloudy":              "",
        "Fog":                 "",
        "HeavyRain":           "",
        "HeavyShowers":        "",
        "HeavySnow":           "",
        "HeavySnowShowers":    "",
        "LightRain":           "",
        "LightShowers":        "",
        "LightSleet":          "",
        "LightSleetShowers":   "",
        "LightSnow":           "",
        "LightSnowShowers":    "",
        "PartlyCloudy":        "󰖕",
        "Sunny":               "",
        "ThunderyHeavyRain":   "",
        "ThunderyShowers":     "",
        "ThunderySnowShowers": "",
        "VeryCloudy": "",
    }

    WEATHER_CODES_WI_DAY = {key: WEATHER_SYMBOL_WI_DAY[value] for key, value in WWO_CODE.items()}

    WEATHER_SYMBOL_WI_NIGHT = {
        "Unknown":             "",
        "Cloudy":              "",
        "Fog":                 "",
        "HeavyRain":           "",
        "HeavyShowers":        "",
        "HeavySnow":           "",
        "HeavySnowShowers":    "",
        "LightRain":           "",
        "LightShowers":        "",
        "LightSleet":          "",
        "LightSleetShowers":   "",
        "LightSnow":           "",
        "LightSnowShowers":    "",
        "PartlyCloudy":        "󰼱",
        "Sunny":               "󰖔",
        "ThunderyHeavyRain":   "",
        "ThunderyShowers":     "",
        "ThunderySnowShowers": "",
        "VeryCloudy": "",
    }

    WEATHER_CODES_WI_NIGHT = {key: WEATHER_SYMBOL_WI_NIGHT[value] for key, value in WWO_CODE.items()}

    WEATHER_SYMBOL_WEGO = {
        "Unknown": [
            "    .-.      ",
            "     __)     ",
            "    (        ",
            "     `-’     ",
            "      •      "],
        "Sunny": [
            '<span foreground=\"#FFFF00\">    \\   /    </span>',
            '<span foreground=\"#FFFF00\">     .-.     </span>',
            '<span foreground=\"#FFFF00\">  ― (   ) ―  </span>',
            '<span foreground=\"#FFFF00\">     `-’     </span>',
            '<span foreground=\"#FFFF00\">    /   \\    </span>'],
        "PartlyCloudy": [
            '<span foreground=\"#FFFF00\">   \\  /      </span>',
            '<span foreground=\"#FFFF00\"> _ /\'\'</span>"<span foreground=\"#BBBBBB\">.-.    </span>',
            '<span foreground=\"#FFFF00\">   \\_</span>"<span foreground=\"#BBBBBB\">(   ).  </span>',
            '<span foreground=\"#FFFF00\">   /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
            '             '
            ],
        "Cloudy": [
            '             ',
            '<span foreground=\"#BBBBBB\">     .--.    </span>',
            '<span foreground=\"#BBBBBB\">  .-(    ).  </span>',
            '<span foreground=\"#BBBBBB\"> (___.__)__) </span>',
            '             '],
        "VeryCloudy": [
            '             ',
            '<span foreground=\"#585858\" font-weight="bold">     .--.    </span>',
            '<span foreground=\"#585858\" font-weight="bold">  .-(    ).  </span>',
            '<span foreground=\"#585858\" font-weight="bold"> (___.__)__) </span>',
            '             '],
        "LightShowers": [
            '<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-.    </span>',
            '<span foreground=\"#FFFF00\">  ,\\_</span>"<span foreground=\"#BBBBBB\">(   ).  </span>',
            '<span foreground=\"#FFFF00\">   /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
            '<span foreground=\"#87afff\">     ‘ ‘ ‘ ‘ </span>',
            '<span foreground=\"#87afff\">    ‘ ‘ ‘ ‘  </span>'],
        "HeavyShowers": [
            '<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#585858\" font-weight="bold">.-.    </span>',
            '<span foreground=\"#FFFF00\">  ,\\_</span>"<span foreground=\"#585858\" font-weight="bold">(   ).  </span>',
            '<span foreground=\"#FFFF00\">   /</span>"<span foreground=\"#585858\" font-weight="bold">(___(__) </span>',
            '<span foreground=\"#0000ff\" font-weight="bold">   ‚‘‚‘‚‘‚‘  </span>',
            '<span foreground=\"#0000ff\" font-weight="bold">   ‚’‚’‚’‚’  </span>'],
        "LightSnowShowers": [
            '<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-.    </span>',
            '<span foreground=\"#FFFF00\">  ,\\_</span>"<span foreground=\"#BBBBBB\">(   ).  </span>',
            '<span foreground=\"#FFFF00\">   /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
            '<span foreground=\"#eeeeee\">     *  *  * </span>',
            '<span foreground=\"#eeeeee\">    *  *  *  </span>'],
        "HeavySnowShowers": [
            '<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#585858\" font-weight="bold">.-.    </span>',
            '<span foreground=\"#FFFF00\">  ,\\_</span>"<span foreground=\"#585858\" font-weight="bold">(   ).  </span>',
            '<span foreground=\"#FFFF00\">   /</span>"<span foreground=\"#585858\" font-weight="bold">(___(__) </span>',
            '<span foreground=\"#eeeeee\" font-weight="bold">    * * * *  </span>',
            '<span foreground=\"#eeeeee\" font-weight="bold">   * * * *   </span>'],
        "LightSleetShowers": [
            '<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-.    </span>',
            '<span foreground=\"#FFFF00\">  ,\\_</span>"<span foreground=\"#BBBBBB\">(   ).  </span>',
            '<span foreground=\"#FFFF00\">   /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
            '<span foreground=\"#87afff\">     ‘ </span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#87afff\"> ‘ </span>"<span foreground=\"#eeeeee\">* </span>',
            '<span foreground=\"#eeeeee\">    *</span>"<span foreground=\"#87afff\"> ‘ </span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#87afff\"> ‘  </span>'],
        "ThunderyShowers": [
            '<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-.    </span>',
            '<span foreground=\"#FFFF00\">  ,\\_</span>"<span foreground=\"#BBBBBB\">(   ).  </span>',
            '<span foreground=\"#FFFF00\">   /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
            '<span foreground=\"#ffff87\">    ⚡\\</span>"<span foreground=\"#87afff\">‘ ‘</span>"<span foreground=\"#ffff87\">⚡\\</span>"<span foreground=\"#87afff\">‘ ‘ </span>',
            '<span foreground=\"#87afff\">    ‘ ‘ ‘ ‘  </span>'],
        "ThunderyHeavyRain": [
            '<span foreground=\"#585858\" font-weight="bold">     .-.     </span>',
            '<span foreground=\"#585858\" font-weight="bold">    (   ).   </span>',
            '<span foreground=\"#585858\" font-weight="bold">   (___(__)  </span>',
            '<span foreground=\"#0000ff\" font-weight="bold">  ‚‘</span>"<span foreground=\"#ffff87\">⚡\\</span>"<span foreground=\"#0000ff\">‘‚</span>"<span foreground=\"#ffff87\">⚡\\</span>"<span foreground=\"#0000ff\">‚‘ </span>',
            '<span foreground=\"#0000ff\" font-weight="bold">  ‚’‚’</span>"<span foreground=\"#ffff87\">⚡\\</span>"<span foreground=\"#0000ff\">’‚’  </span>'],
        "ThunderySnowShowers": [
            '<span foreground=\"#FFFF00\"> _`/\'\'</span>"<span foreground=\"#BBBBBB\">.-.    </span>',
            '<span foreground=\"#FFFF00\">  ,\\_</span>"<span foreground=\"#BBBBBB\">(   ).  </span>',
            '<span foreground=\"#FFFF00\">   /</span>"<span foreground=\"#BBBBBB\">(___(__) </span>',
            '<span foreground=\"#eeeeee\">     *</span>"<span foreground=\"#ffff87\">⚡\\</span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#ffff87\">⚡\\</span>"<span foreground=\"#eeeeee\">* </span>',
            '<span foreground=\"#eeeeee\">    *  *  *  </span>'],
        "LightRain": [
            '<span foreground=\"#BBBBBB\">     .-.     </span>',
            '<span foreground=\"#BBBBBB\">    (   ).   </span>',
            '<span foreground=\"#BBBBBB\">   (___(__)  </span>',
            '<span foreground=\"#87afff\">    ‘ ‘ ‘ ‘  </span>',
            '<span foreground=\"#87afff\">   ‘ ‘ ‘ ‘   </span>'],
        "HeavyRain": [
            '<span foreground=\"#585858\" font-weight="bold">     .-.     </span>',
            '<span foreground=\"#585858\" font-weight="bold">    (   ).   </span>',
            '<span foreground=\"#585858\" font-weight="bold">   (___(__)  </span>',
            '<span foreground=\"#0000ff\" font-weight="bold">  ‚‘‚‘‚‘‚‘   </span>',
            '<span foreground=\"#0000ff\" font-weight="bold">  ‚’‚’‚’‚’   </span>'],
        "LightSnow": [
            '<span foreground=\"#BBBBBB\">     .-.     </span>',
            '<span foreground=\"#BBBBBB\">    (   ).   </span>',
            '<span foreground=\"#BBBBBB\">   (___(__)  </span>',
            '<span foreground=\"#eeeeee\">    *  *  *  </span>',
            '<span foreground=\"#eeeeee\">   *  *  *   </span>'],
        "HeavySnow": [
            '<span foreground=\"#585858\" font-weight="bold">     .-.     </span>',
            '<span foreground=\"#585858\" font-weight="bold">    (   ).   </span>',
            '<span foreground=\"#585858\" font-weight="bold">   (___(__)  </span>',
            '<span foreground=\"#eeeeee\" font-weight="bold">   * * * *   </span>',
            '<span foreground=\"#eeeeee\" font-weight="bold">  * * * *    </span>'],
        "LightSleet": [
            '<span foreground=\"#BBBBBB\">     .-.     </span>',
            '<span foreground=\"#BBBBBB\">    (   ).   </span>',
            '<span foreground=\"#BBBBBB\">   (___(__)  </span>',
            '<span foreground=\"#87afff\">    ‘ </span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#87afff\"> ‘ </span>"<span foreground=\"#eeeeee\">*  </span>',
            '<span foreground=\"#eeeeee\">   *</span>"<span foreground=\"#87afff\"> ‘ </span>"<span foreground=\"#eeeeee\">*</span>"<span foreground=\"#87afff\"> ‘   </span>'],
        "Fog": [
            '             ',
            '<span foreground=\"#c0c0c0\"> _ - _ - _ - </span>',
            '<span foreground=\"#c0c0c0\">  _ - _ - _  </span>',
            '<span foreground=\"#c0c0c0\"> _ - _ - _ - </span>',
            '             '],
    }

    WEATHER_CODES_WEGO = {key: WEATHER_SYMBOL_WEGO[value] for key, value in WWO_CODE.items()}

    CACHE_DIR = os.path.join(os.environ.get("XDG_CACHE_HOME", os.path.expanduser("~/.cache")), "waybar-weather")
    CACHE_FILE = os.path.join(CACHE_DIR, "wttr.json")
    CACHE_MOON_FILE = os.path.join(CACHE_DIR, "moon.json")
    CACHE_MOON_ICON_FILE = os.path.join(CACHE_DIR, "moon-icon")
    CACHE_TTL = timedelta(minutes=10)

    data = {}
    data["text"] = ""

    def format_time(time):
        return datetime.strptime(format_24_time(time), "%H").strftime("%I %p")

    def format_24_time(time):
        return time.replace("00", "").zfill(2)

    def format_temp(temp):
        return (str(temp) + "°").ljust(3)

    def format_chances(hour):
        chances = {
            "chanceoffog": "Fog",
            "chanceoffrost": "Frost",
            "chanceofovercast": "Overcast",
            "chanceofrain": "Rain",
            "chanceofsnow": "Snow",
            "chanceofsunshine": "Sunshine",
            "chanceofthunder": "Thunder",
            "chanceofwindy": "Wind",
        }
        conditions = []
        for chance, event in chances.items():
            if int(hour.get(chance, 0)) > 0:
                conditions.append(event + " " + str(hour[chance]) + "%")
        return ", ".join(conditions)

    def deg_to_compass(num):
        val = int((num / 22.5) + 0.5)
        arr = ["N", "NNE", "NE", "ENE", "E", "ESE", "SE", "SSE", "S", "SSW", "SW", "WSW", "W", "WNW", "NW", "NNW"]
        return arr[(val % 16)]

    def build_text(current_condition):
        feels_like_f = current_condition["FeelsLikeF"]
        weather_code = current_condition["weatherCode"]
        # Check if we have a mapped format; if not, fallback to Unknown
        if weather_code not in WEATHER_CODES:
            weather_code = "113" # Fallback to sunny/default to prevent crash

        tempint = int(float(feels_like_f)) # float cast just in case
        extrachar = ""
        if 0 < tempint < 10:
            extrachar = "+"

        current_weather = f"{WEATHER_CODES[weather_code]} {extrachar} {int(feels_like_f)}°F"
        return current_weather

    def build_tooltip(current_condition, astronomy, moon_icon):
        weather_description = current_condition['weatherDesc'][0]['value']
        feels_like_f = current_condition["FeelsLikeF"]
        temp_f = current_condition['temp_F']
        humidity = current_condition['humidity']
        wind_speed = current_condition['windspeedMiles']
        wind_dir = current_condition['winddir16Point']
        moon_phase = astronomy.get('moon_phase', 'Unknown')
        
        weather_code = current_condition['weatherCode']
        if weather_code not in WEATHER_CODES_WEGO:
            weather_code = "113"

        wego = WEATHER_CODES_WEGO[weather_code]

        current = f"{wego[0]}{weather_description} {temp_f}°\n"
        feels = f"{wego[1]}Feels like: {feels_like_f}°\n"
        wind = f"{wego[2]}Wind: {wind_speed}mph {WIND_DIRECTION.get(wind_dir, ''\'')}\n" # Safe get for direction
        humidityl = f"{wego[3]}Humidity: {humidity}%\n"
        moon = f"{wego[4]}Moon phase: {moon_phase} " + moon_icon + "\n"

        tooltip = current + feels + wind + humidityl + moon
        return tooltip

    def build_forecast(weather):
        tooltip = "\n"
        for i, day in enumerate(weather):
            if i == 0:
                tooltip += "Today, "
            if i == 1:
                tooltip += "Tomorrow, "
            
            date = datetime.strptime(day['date'], "%Y-%m-%d").strftime("%a %b %d %Y")
            tooltip += f"<b>{date}</b>\n"
            
            max_temp = day['maxtempF']
            min_temp = day['mintempF']
            tooltip += f" {max_temp}°F  {min_temp}°F"

            sunrise = day['astronomy'][0]['sunrise']
            sunset = day['astronomy'][0]['sunset']
            tooltip += f" {sunrise}  {sunset}\n"

            tooltip += build_hourly_forecast(i, day['hourly'], sunrise, sunset)
        return tooltip

    def build_hourly_forecast(day_num, hourly, sunrise, sunset):
        try:
            sunrise_hour = datetime.strptime(sunrise, "%I:%M %p").hour
            sunset_hour = datetime.strptime(sunset, "%I:%M %p").hour
        except ValueError:
            # Fallback if time format is different (OpenMeteo might send 24h)
            sunrise_hour = int(sunrise.split(':')[0])
            sunset_hour = int(sunset.split(':')[0])

        current_hour = datetime.now().hour
        tooltip = ""

        for hour in hourly:
            time_24_hr = int(format_24_time(hour["time"]))
            if day_num == 0:
                if time_24_hr < current_hour - 2:
                    continue

            if is_night_hour(time_24_hr, sunrise_hour, sunset_hour):
                codes = WEATHER_CODES_WI_NIGHT
            else:
                codes = WEATHER_CODES_WI_DAY

            current_time = format_time(hour['time'])
            wcode = hour['weatherCode']
            if wcode not in codes: wcode = "113" # Fallback

            current_weather_code = codes[wcode]
            feels_like = format_temp(hour['FeelsLikeF'])
            weather_desc = hour['weatherDesc'][0]['value']
            current_chances = format_chances(hour)

            tooltip += f"{current_time} {current_weather_code} "
            tooltip += f"{feels_like} {weather_desc}, {current_chances}\n"

        return tooltip

    def is_night_hour(time_24_hr, sunrise_hour, sunset_hour):
        before_sunrise = time_24_hr < sunrise_hour
        after_sunset = time_24_hr > sunset_hour
        return after_sunset or before_sunrise

    def load_cache(path, ttl):
        try:
            if not os.path.exists(path):
                return None
            mtime = datetime.fromtimestamp(os.path.getmtime(path))
            if datetime.now() - mtime > ttl:
                return None
            with open(path, "r") as f:
                if path.endswith(".json"):
                    return json.load(f)
                return f.read().strip()
        except Exception:
            return None

    def save_cache(path, data):
        os.makedirs(os.path.dirname(path), exist_ok=True)
        tmp = path + ".tmp"
        try:
            with open(tmp, "w") as f:
                if isinstance(data, dict):
                    json.dump(data, f)
                else:
                    f.write(str(data))
            shutil.move(tmp, path)
        except Exception:
            pass

    # --- OPEN-METEO INTEGRATION HELPER FUNCTIONS ---

    def get_lat_lon():
        """Attempt to get location via IP if using OpenMeteo"""
        try:
            resp = requests.get("http://ip-api.com/json/", timeout=5).json()
            return resp.get('lat'), resp.get('lon')
        except:
            # Default to a generic location if IP fetch fails (NYC)
            return 40.71, -74.00

    def fetch_open_meteo():
        """Fetch and Transform OpenMeteo data to match Wttr.in JSON structure"""
        lat, lon = get_lat_lon()
        url = "https://api.open-meteo.com/v1/forecast"
        params = {
            "latitude": lat,
            "longitude": lon,
            "current": "temperature_2m,apparent_temperature,precipitation,weather_code,wind_speed_10m,wind_direction_10m,relative_humidity_2m",
            "daily": "weather_code,temperature_2m_max,temperature_2m_min,sunrise,sunset,precipitation_probability_max",
            "hourly": "temperature_2m,apparent_temperature,precipitation_probability,weather_code",
            "temperature_unit": "fahrenheit",
            "wind_speed_unit": "mph",
            "precipitation_unit": "inch",
            "timezone": "auto"
        }
        
        response = requests.get(url, params=params, timeout=10)
        om_data = response.json()
        
        # Transform Current Condition
        current = om_data["current"]
        wmo_code = current["weather_code"]
        wwo_code = WMO_TO_WWO.get(wmo_code, "113")
        
        wttr_current = {
            "temp_F": str(int(current["temperature_2m"])),
            "FeelsLikeF": str(int(current["apparent_temperature"])),
            "weatherCode": wwo_code,
            "weatherDesc": [{"value": WWO_CODE.get(wwo_code, "Unknown")}],
            "humidity": str(current["relative_humidity_2m"]),
            "windspeedMiles": str(int(current["wind_speed_10m"])),
            "winddir16Point": deg_to_compass(current["wind_direction_10m"]),
        }
        
        # Transform Daily Forecast (OpenMeteo gives 7 days, we need 3)
        wttr_weather = []
        daily = om_data["daily"]
        hourly = om_data["hourly"]
        
        for i in range(3):
            date_str = daily["time"][i]
            
            # Build Hourly for this day (wttr uses 3-hour intervals: 0, 300, 600...)
            # OpenMeteo gives 0, 1, 2...
            wttr_hourly = []
            for h in range(0, 24, 3): # Step by 3 hours to mimic wttr
                idx = (i * 24) + h
                h_code = hourly["weather_code"][idx]
                h_wwo = WMO_TO_WWO.get(h_code, "113")
                
                wttr_hourly.append({
                    "time": str(h * 100), # 0, 300, 600
                    "weatherCode": h_wwo,
                    "weatherDesc": [{"value": WWO_CODE.get(h_wwo, "Unknown")}],
                    "FeelsLikeF": str(int(hourly["apparent_temperature"][idx])),
                    "chanceofrain": str(hourly["precipitation_probability"][idx]),
                    # Fill other chances with 0 as API doesn't provide them easily
                    "chanceoffog": "0", "chanceofsnow": "0", "chanceofthunder": "0",
                    "chanceofwindy": "0", "chanceofsunshine": "0" 
                })

            # Astronomy
            sunrise = datetime.fromisoformat(daily["sunrise"][i]).strftime("%I:%M %p")
            sunset = datetime.fromisoformat(daily["sunset"][i]).strftime("%I:%M %p")
            
            wttr_weather.append({
                "date": date_str,
                "maxtempF": str(int(daily["temperature_2m_max"][i])),
                "mintempF": str(int(daily["temperature_2m_min"][i])),
                "astronomy": [{"sunrise": sunrise, "sunset": sunset, "moon_phase": "Unknown"}],
                "hourly": wttr_hourly
            })
            
        return {
            "current_condition": [wttr_current],
            "weather": wttr_weather
        }

    def get_wttr_json(hyprlock=False):
        # Try loading cached JSON
        cached = load_cache(CACHE_FILE, CACHE_TTL)
        cached_moon = load_cache(CACHE_MOON_FILE, CACHE_TTL)
        cached_moon_icon = load_cache(CACHE_MOON_ICON_FILE, CACHE_TTL)

        if cached and cached_moon and cached_moon_icon:
            weather = cached
            current_condition = weather["current_condition"][0]
            astronomy = cached_moon
            moon_icon = cached_moon_icon
        else:
            try:
                # Primary Source: wttr.in
                weather = requests.get("https://wttr.in/?u&format=j1", timeout=5).json()
                moon = requests.get("https://wttr.in/?format=%m", timeout=5)
                moon_icon = moon.text
                
                current_condition = weather["current_condition"][0]
                astronomy = weather["weather"][0]['astronomy'][0]
            except Exception:
                # Fallback Source: Open-Meteo
                try:
                    print("open_mateo fallback")
                    weather = fetch_open_meteo()
                    current_condition = weather["current_condition"][0]
                    astronomy = weather["weather"][0]['astronomy'][0]
                    moon_icon = "" # Generic moon icon for fallback
                except Exception as e:
                    # If both fail
                    raise e

            # Save cache (works for both sources since we transformed OM data)
            save_cache(CACHE_FILE, weather)
            save_cache(CACHE_MOON_FILE, astronomy)
            save_cache(CACHE_MOON_ICON_FILE, moon_icon)

        if hyprlock:
            return build_tooltip(current_condition, astronomy, moon_icon)
        else:
            text = build_text(current_condition)
            tooltip = build_tooltip(current_condition, astronomy, moon_icon) + build_forecast(weather["weather"])
            data["text"] = text
            data["tooltip"] = tooltip
            return json.dumps(data)

    def main():
        if args.hyprlock:
            try:
                print(get_wttr_json(hyprlock=True))
            except Exception as e:
                print("error")
                # print(e) # Uncomment for debug
        else:
            try:
                print(get_wttr_json())
            except Exception as e:
                print(json.dumps({"text": "Err", "tooltip": str(e)}))

    if __name__ == "__main__":
        main()

  '';
in
{
  imports = [ ../options.nix ];

  config = lib.mkIf cfg.enable {
    home.packages = [ waybar-weather ];
  };
}
