#!/bin/sh
# weather - query current weather and forecasts for any location via wttr.in.
#
# wttr.in (https://github.com/chubin/wttr.in) is a console-oriented weather
# service backed by World Weather Online data. It supports several output
# formats: a graphical ANSI view for terminals (the default), one-line text
# formats (built-in presets 1-4 or a custom %-notation string), a rich JSON
# document (?format=j1 / j2) for scripts and APIs, plus PNG / HTML /
# Prometheus metrics.
#
# This script is a thin, friendly wrapper around the wttr.in HTTP API. It
# builds the request URL from the supplied location and options, fetches the
# data with curl and (when JSON is requested) pretty-prints it with jq.
#
# Usage:
#   weather [options] [location]
#
# Options:
#   -l, --location LOC   Location: city, airport code, domain, IP,
#                        "lat,lon" coordinates, or "~Name" for a custom label.
#                        Default: auto-detect from the request IP.
#   -u, --units U        Unit system: m (metric, default), u (USCS/imperial),
#                        M (metric with wind speed in m/s).
#   -L, --lang LANG      Output language code, e.g. de, fr, ru, zh-cn.
#   -f, --format FMT     Output format:
#                          j1  -> rich JSON document (default for --json)
#                          j2  -> JSON document, imperial units
#                          1-4 -> built-in one-line presets
#                          "%..." -> custom one-line %-notation format
#                        Omit to get the default graphical terminal view.
#   -j, --json           Alias for --format j1 (emit JSON).
#   -0                  Current weather only.
#   -1                  Current weather + today's forecast.
#   -2                  Current weather + today's + tomorrow's forecast.
#   -q, --quiet          Quiet: no "Weather report" header / city name.
#   -A                  Force ANSI output (ignore User-Agent detection).
#   -h, --help           Show this help text.
#
# Environment:
#   WTTRAPI          Base endpoint. Default: https://wttr.in
#   WEATHER_TIMEOUT  curl connect/read timeout in seconds. Default: 20
#
# Dependencies: curl, jq (jq only needed for the JSON format).
#
# Examples:
#   weather
#   weather London
#   weather -u u -L de Berlin
#   weather -f 3 "New York"
#   weather -f "%l: %c %t (feels %f), wind %w %m" Paris
#   weather -j Tokyo

set -eu

WTTRAPI="${WTTRAPI:-https://wttr.in}"
TIMEOUT="${WEATHER_TIMEOUT:-20}"

# Single-letter options (view/quiet/units) concatenated into one run.
SHORT=""
LANG_CODE=""
FORMAT=""
LOCATION=""

usage() {
  sed -n '/^# Usage:/,/^# Examples:/p' "$0" | sed 's/^# \{0,1\}//'
}

# --- Parse arguments. ---
while [ "$#" -gt 0 ]; do
  case "$1" in
    -h|--help)
      usage
      exit 0
      ;;
    -l|--location)
      [ "$#" -ge 2 ] || { echo "weather: $1 requires an argument" >&2; exit 1; }
      LOCATION="$2"
      shift 2
      ;;
    -u|--units)
      [ "$#" -ge 2 ] || { echo "weather: $1 requires an argument" >&2; exit 1; }
      case "$2" in
        m|u|M) SHORT="${SHORT}$2" ;;
        *) echo "weather: unknown unit '$2' (use m, u or M)" >&2; exit 1 ;;
      esac
      shift 2
      ;;
    -L|--lang)
      [ "$#" -ge 2 ] || { echo "weather: $1 requires an argument" >&2; exit 1; }
      LANG_CODE="$2"
      shift 2
      ;;
    -f|--format)
      [ "$#" -ge 2 ] || { echo "weather: $1 requires an argument" >&2; exit 1; }
      FORMAT="$2"
      shift 2
      ;;
    -j|--json)
      FORMAT="j1"
      shift
      ;;
    -0|-1|-2|-q|-A)
      SHORT="${SHORT}${1#-}"
      shift
      ;;
    --)
      shift
      LOCATION="${LOCATION:+$LOCATION }$(printf '%s' "$*" | sed 's/^ //')"
      break
      ;;
    -*)
      echo "weather: unknown option '$1' (try --help)" >&2
      exit 1
      ;;
    *)
      # Positional: append to location (preserves multi-word locations).
      LOCATION="${LOCATION:+$LOCATION }$1"
      shift
      ;;
  esac
done

# --- Assemble the query string. ---
# wttr.in accepts a leading run of single-letter options, then '&'-joined
# long options (key=value). We build both parts and join them.
QUERY="$SHORT"

# Long options: format and lang.
LONG=""
if [ -n "$FORMAT" ]; then
  case "$FORMAT" in
    j1|j2)
      LONG="${LONG:+$LONG&}format=${FORMAT}"
      ;;
    [1-4])
      LONG="${LONG:+$LONG&}format=${FORMAT}"
      ;;
    *)
      # Custom %-notation one-line format -> URL-encode it.
      ENC=$(printf '%s' "$FORMAT" | jq -sRr @uri)
      LONG="${LONG:+$LONG&}format=${ENC}"
      ;;
  esac
fi
if [ -n "$LANG_CODE" ]; then
  LONG="${LONG:+$LONG&}lang=$(printf '%s' "$LANG_CODE" | jq -sRr @uri)"
fi

# Combine short + long parts into a single query string.
if [ -n "$QUERY" ] && [ -n "$LONG" ]; then
  QUERY="${QUERY}&${LONG}"
elif [ -z "$QUERY" ] && [ -n "$LONG" ]; then
  QUERY="$LONG"
fi

# URL-encode the location (spaces -> %20, etc.). Empty means auto-detect.
if [ -n "$LOCATION" ]; then
  LOC_ENC=$(printf '%s' "$LOCATION" | jq -sRr @uri)
else
  LOC_ENC=""
fi

URL="${WTTRAPI}/${LOC_ENC}"
if [ -n "$QUERY" ]; then
  URL="${URL}?${QUERY}"
fi

# --- Fetch. ---
# wttr.in returns the graphical ANSI art whenever the request looks like it
# comes from a console client (curl's default User-Agent), and HTML for
# browsers. So we keep curl's default identity. The "-A" flag above is a
# wttr.in URL option ("force ANSI") and is already part of the query string.

RESP=$(curl -s -L --max-time "$TIMEOUT" "$URL") || {
  echo "weather: failed to reach $WTTRAPI" >&2
  exit 1
}

# --- Emit. ---
if [ "$FORMAT" = "j1" ] || [ "$FORMAT" = "j2" ]; then
  if command -v jq >/dev/null 2>&1; then
    printf '%s\n' "$RESP" | jq . 2>/dev/null || printf '%s\n' "$RESP"
  else
    printf '%s\n' "$RESP"
  fi
else
  printf '%s\n' "$RESP"
fi

exit 0
