#!/bin/bash
# Supervolcano Monitor - Live Volcanic Surveillance Grid
# Fetches seismograms, webcams, and earthquake data for Earth's supervolcanoes
# Assembles a monitoring dashboard grid via ImageMagick montage
# Alias: svm
#
# Tracked: Yellowstone | Long Valley | Campi Flegrei | Taupo | Toba | Aira
# Sources: USGS Earthquake Hazards, USGS HANS, GeoNet NZ
# Requires: curl, jq, imagemagick, mpv

export DISPLAY=:0

# ═══════════════════════════════════════════════════════════════
# CONFIGURATION
# ═══════════════════════════════════════════════════════════════

cache="$HOME/.cache/maritime/supervolcano"
grid_file="$cache/grid.png"
mkdir -p "$cache"

PW=640 PH=480

# Fonts
FONT_BOLD=$(fc-match -f '%{file}' 'DejaVu Sans:Bold' 2>/dev/null)
FONT_REG=$(fc-match -f '%{file}' 'DejaVu Sans' 2>/dev/null)
FB=() FR=()
[ -n "$FONT_BOLD" ] && FB=(-font "$FONT_BOLD")
[ -n "$FONT_REG" ] && FR=(-font "$FONT_REG")

# Grid layout order (3 columns x 2 rows)
ORDER=(yellowstone longvalley campi_flegrei taupo toba aira)

# ═══════════════════════════════════════════════════════════════
# VOLCANO DEFINITIONS
# ═══════════════════════════════════════════════════════════════

declare -A VNAME VLOC VBBOX VVNUM VIMG

VNAME=( [yellowstone]="YELLOWSTONE"    [longvalley]="LONG VALLEY"
        [campi_flegrei]="CAMPI FLEGREI" [taupo]="TAUPO"
        [toba]="TOBA"                   [aira]="AIRA" )

VLOC=( [yellowstone]="Wyoming, USA"     [longvalley]="California, USA"
       [campi_flegrei]="Naples, Italy"   [taupo]="New Zealand"
       [toba]="Sumatra, Indonesia"       [aira]="Kagoshima, Japan" )

# Bounding boxes: minlat|maxlat|minlon|maxlon
VBBOX=( [yellowstone]="44.0|45.0|-111.5|-109.5"
        [longvalley]="37.4|38.0|-119.3|-118.5"
        [campi_flegrei]="40.6|40.95|13.9|14.25"
        [taupo]="-39.0|-38.0|175.5|176.5"
        [toba]="2.0|3.0|98.0|99.5"
        [aira]="31.3|31.8|130.4|131.0" )

# USGS HANS volcano numbers (US volcanoes only)
VVNUM=( [yellowstone]="325010" [longvalley]="323822" )

# Live image sources (seismograms / webcams)
VIMG=( [yellowstone]="https://earthquake.usgs.gov/static/earthquake-network-operations/Seismic_Data/telemetry_data/LKWY_24hr.png"
       [taupo]="https://images.geonet.org.nz/volcano/cameras/latest/ruapehunorth.jpg" )

# Alternate images for slideshow mode
declare -A VIMG_ALT
VIMG_ALT=(
    [yellowstone_flwy]="https://earthquake.usgs.gov/static/earthquake-network-operations/Seismic_Data/telemetry_data/FLWY_24hr.png"
    [yellowstone_snow]="https://earthquake.usgs.gov/static/earthquake-network-operations/Seismic_Data/telemetry_data/SNOW_24hr.png"
    [taupo_tongariro]="https://images.geonet.org.nz/volcano/cameras/latest/tongariro.jpg"
    [taupo_ngauruhoe]="https://images.geonet.org.nz/volcano/cameras/latest/ngauruhoe.jpg"
)

# ═══════════════════════════════════════════════════════════════
# DATA FETCHING
# ═══════════════════════════════════════════════════════════════

# Earthquake count for a volcano's bounding box (last 7 days)
fetch_quake_count() {
    local key="$1"
    IFS='|' read -r minlat maxlat minlon maxlon <<< "${VBBOX[$key]}"
    local start
    start=$(date -u -d '7 days ago' +%Y-%m-%d)
    local count
    count=$(curl -sf "https://earthquake.usgs.gov/fdsnws/event/1/count?format=text&starttime=${start}&minlatitude=${minlat}&maxlatitude=${maxlat}&minlongitude=${minlon}&maxlongitude=${maxlon}")
    echo "${count:-0}" > "$cache/count_${key}.txt"
}

# USGS HANS alert level
fetch_usgs_alert() {
    local key="$1"
    local vnum="${VVNUM[$key]}"
    [ -z "$vnum" ] && return
    local json
    json=$(curl -sf "https://volcanoes.usgs.gov/hans-public/api/volcano/getVolcano/${vnum}")
    local alert
    alert=$(echo "$json" | jq -r '.alertLevel // "NORMAL"' 2>/dev/null)
    echo "${alert:-NORMAL}" > "$cache/alert_${key}.txt"
}

# GeoNet NZ alert levels
fetch_geonet_alerts() {
    local json
    json=$(curl -sf "https://api.geonet.org.nz/volcano/val")
    local level
    level=$(echo "$json" | jq -r '[.features[] | select(.properties.volcanoID | test("taupo";"i"))][0].properties.level // 0' 2>/dev/null)
    case "$level" in
        0) echo "NORMAL" ;;
        1) echo "MINOR UNREST" ;;
        2) echo "MODERATE UNREST" ;;
        3) echo "MINOR ERUPTION" ;;
        4) echo "MODERATE ERUPTION" ;;
        5) echo "MAJOR ERUPTION" ;;
        *) echo "NORMAL" ;;
    esac > "$cache/alert_taupo.txt"
}

# Fetch live image for a volcano
fetch_live_image() {
    local key="$1"
    local url="${VIMG[$key]}"
    [ -z "$url" ] && return 1
    curl -sLo "$cache/raw_${key}.img" "$url"
}

# ═══════════════════════════════════════════════════════════════
# PANEL GENERATION
# ═══════════════════════════════════════════════════════════════

# Alert level -> color
alert_color() {
    case "$1" in
        NORMAL) echo "#3fb950" ;;
        ADVISORY|"MINOR UNREST") echo "#d29922" ;;
        WATCH|"MODERATE UNREST") echo "#db6d28" ;;
        WARNING|*ERUPTION*) echo "#f85149" ;;
        *) echo "#8b949e" ;;
    esac
}

# Generate status card (no live image available)
make_card() {
    local key="$1"
    local name="${VNAME[$key]}"
    local loc="${VLOC[$key]}"
    local quakes alert ac
    quakes=$(cat "$cache/count_${key}.txt" 2>/dev/null || echo "?")
    alert=$(cat "$cache/alert_${key}.txt" 2>/dev/null || echo "—")
    ac=$(alert_color "$alert")

    magick -size ${PW}x${PH} xc:'#0d1117' \
        "${FB[@]}" \
        -fill '#58a6ff' -pointsize 36 -gravity North -annotate +0+30 "$name" \
        "${FR[@]}" \
        -fill '#8b949e' -pointsize 20 -annotate +0+75 "$loc" \
        -fill white -pointsize 80 -gravity Center -annotate +0-20 "$quakes" \
        -fill '#8b949e' -pointsize 16 -annotate +0+45 "earthquakes (7 days)" \
        "${FB[@]}" \
        -fill "$ac" -pointsize 22 -gravity South -annotate +0+30 "$alert" \
        "$cache/panel_${key}.png"
}

# Label a live image with overlay
make_labeled() {
    local key="$1"
    local name="${VNAME[$key]}"
    local loc="${VLOC[$key]}"
    local quakes
    quakes=$(cat "$cache/count_${key}.txt" 2>/dev/null || echo "?")
    local input="$cache/raw_${key}.img"
    local output="$cache/panel_${key}.png"

    [ ! -f "$input" ] || [ ! -s "$input" ] && make_card "$key" && return

    magick "$input" \
        -resize ${PW}x${PH}! \
        -fill 'rgba(0,0,0,0.7)' -draw "rectangle 0,0 ${PW},60" \
        -fill 'rgba(0,0,0,0.7)' -draw "rectangle 0,$((PH-40)) ${PW},${PH}" \
        "${FB[@]}" \
        -fill '#58a6ff' -pointsize 26 -gravity NorthWest -annotate +10+16 "$name" \
        "${FR[@]}" \
        -fill '#8b949e' -pointsize 16 -gravity NorthEast -annotate +10+22 "$loc" \
        -fill white -pointsize 16 -gravity SouthWest -annotate +10+12 "Quakes (7d): $quakes" \
        "${FB[@]}" \
        -fill '#3fb950' -pointsize 16 -gravity SouthEast -annotate +10+12 "LIVE" \
        "$output"
}

# Build panel for a volcano (picks labeled or card)
make_panel() {
    local key="$1"
    if [ -n "${VIMG[$key]}" ] && [ -f "$cache/raw_${key}.img" ] && [ -s "$cache/raw_${key}.img" ]; then
        make_labeled "$key"
    else
        make_card "$key"
    fi
}

# ═══════════════════════════════════════════════════════════════
# GRID ASSEMBLY
# ═══════════════════════════════════════════════════════════════

generate_grid() {
    local panels=()
    for key in "${ORDER[@]}"; do
        make_panel "$key"
        panels+=("$cache/panel_${key}.png")
    done

    montage "${panels[@]}" \
        -tile 3x2 -geometry ${PW}x${PH}+4+4 \
        -background '#010409' \
        "${FB[@]}" -fill '#58a6ff' -pointsize 22 \
        -title "SUPERVOLCANO MONITOR  ·  $(date -u '+%Y-%m-%d %H:%M UTC')" \
        "$grid_file"

    echo "Grid saved: $grid_file"
}

# ═══════════════════════════════════════════════════════════════
# COMMANDS
# ═══════════════════════════════════════════════════════════════

update() {
    echo "Fetching supervolcano data..."

    # Earthquake counts (parallel)
    for key in "${ORDER[@]}"; do
        fetch_quake_count "$key" &
    done

    # Alert levels (parallel)
    fetch_usgs_alert yellowstone &
    fetch_usgs_alert longvalley &
    fetch_geonet_alerts &

    # Live images (parallel)
    for key in "${ORDER[@]}"; do
        [ -n "${VIMG[$key]}" ] && fetch_live_image "$key" &
    done

    # Alternate images (parallel)
    for alt_key in "${!VIMG_ALT[@]}"; do
        curl -sLo "$cache/raw_${alt_key}.img" "${VIMG_ALT[$alt_key]}" &
    done

    wait
    echo "Data fetched. Generating grid..."

    generate_grid
    notify-send -t 3000 -i "$grid_file" "Supervolcano Monitor" "Dashboard updated"
}

# Resolve shorthand volcano name
resolve() {
    case "${1,,}" in
        y*) echo "yellowstone" ;;
        l*|lv) echo "longvalley" ;;
        c*|cf) echo "campi_flegrei" ;;
        ta*|nz) echo "taupo" ;;
        to*) echo "toba" ;;
        a*) echo "aira" ;;
        *) echo "" ;;
    esac
}

# Display grid in mpv
show_grid() {
    [ ! -f "$grid_file" ] && echo "No grid cached. Run: svm update" && return 1
    setsid -f mpv --title="Supervolcano Monitor" --autofit=90% \
        --loop-file=inf "$grid_file"
}

# View specific volcano panel
show_volcano() {
    local key
    key=$(resolve "$1")
    [ -z "$key" ] && echo "Unknown volcano: $1" && return 1
    local panel="$cache/panel_${key}.png"
    [ ! -f "$panel" ] && echo "No data for $key. Run: svm update" && return 1
    setsid -f mpv --title="${VNAME[$key]}" --autofit=60% \
        --loop-file=inf "$panel"
}

# Slideshow of all panels + alternates
show_all() {
    local imgs=()
    for key in "${ORDER[@]}"; do
        [ -f "$cache/panel_${key}.png" ] && imgs+=("$cache/panel_${key}.png")
    done
    for alt_key in "${!VIMG_ALT[@]}"; do
        [ -f "$cache/raw_${alt_key}.img" ] && imgs+=("$cache/raw_${alt_key}.img")
    done
    setsid -f mpv --title="Supervolcano Monitor - All Data" --idle --autofit=70% \
        --loop-playlist --image-display-duration=4 "${imgs[@]}"
}

# Send notification
notify() {
    if [ -n "$1" ]; then
        local key
        key=$(resolve "$1")
        [ -z "$key" ] && return
        local panel="$cache/panel_${key}.png"
        [ -f "$panel" ] && notify-send -t 60000 -i "$panel" "${VNAME[$key]}" "${VLOC[$key]}"
    else
        [ -f "$grid_file" ] && notify-send -t 60000 -i "$grid_file" "Supervolcano Monitor" ""
    fi
}

# Text status report
status() {
    echo "SUPERVOLCANO STATUS — $(date -u '+%Y-%m-%d %H:%M UTC')"
    echo "═══════════════════════════════════════════════════════"
    for key in "${ORDER[@]}"; do
        local quakes alert
        quakes=$(cat "$cache/count_${key}.txt" 2>/dev/null || echo "?")
        alert=$(cat "$cache/alert_${key}.txt" 2>/dev/null || echo "—")
        printf "  %-16s %-22s %4s quakes   %s\n" "${VNAME[$key]}" "${VLOC[$key]}" "$quakes" "$alert"
    done
    echo "═══════════════════════════════════════════════════════"
}

# Help
help() {
    cat << 'EOF'
Supervolcano Monitor - Live Volcanic Surveillance Grid
══════════════════════════════════════════════════════════

Usage: svm <command> [volcano]

Commands:
  update, u              Fetch all data and generate grid
  grid, g                Display cached dashboard grid
  notify, n [volcano]    Send grid/volcano to dunst notification
  images, i [volcano]    View specific volcano panel in mpv
  all                    Slideshow of all panels and alternates
  status, s              Text status report
  help, h                Show this help

Volcanoes:
  yellowstone, y         Yellowstone Caldera (Wyoming, USA)
  longvalley, l          Long Valley Caldera (California, USA)
  campi_flegrei, c       Campi Flegrei (Naples, Italy)
  taupo, t               Taupo Caldera (New Zealand)
  toba, to               Toba Caldera (Sumatra, Indonesia)
  aira, a                Aira Caldera (Kagoshima, Japan)

Examples:
  svm update             Refresh all data and build grid
  svm grid               Open dashboard grid in mpv
  svm images yellowstone View Yellowstone seismogram
  svm notify taupo       Send Taupo webcam to dunst
  svm status             Print text status report

Live Data Sources:
  Yellowstone   USGS 24hr seismogram (LKWY station)
  Taupo         GeoNet Ruapehu North webcam
  All           USGS earthquake API (7-day count)
  US volcanoes  USGS HANS alert levels
  NZ volcanoes  GeoNet volcanic alert levels

Grid Layout (3x2):
  ┌──────────────┬──────────────┬──────────────┐
  │  Yellowstone  │  Long Valley  │ Campi Flegrei │
  │  (seismogram) │  (status)    │  (status)     │
  ├──────────────┼──────────────┼──────────────┤
  │    Taupo     │     Toba     │     Aira      │
  │   (webcam)   │   (status)   │   (status)    │
  └──────────────┴──────────────┴──────────────┘

Requires: curl, jq, imagemagick, mpv
══════════════════════════════════════════════════════════
EOF
}

# Status bar output
tobar() {
    local elevated=false
    for key in "${ORDER[@]}"; do
        local alert
        alert=$(cat "$cache/alert_${key}.txt" 2>/dev/null || echo "NORMAL")
        case "$alert" in
            NORMAL|—) ;;
            *) elevated=true ;;
        esac
    done

    if $elevated; then
        echo " SVM"
    else
        echo " SVM"
    fi
}

# ═══════════════════════════════════════════════════════════════
# MAIN
# ═══════════════════════════════════════════════════════════════

case "$1" in
    u*) update ;;
    g*) show_grid ;;
    n*)
        shift
        notify "$1"
        ;;
    i*)
        shift
        if [ -n "$1" ]; then
            show_volcano "$1"
        else
            show_grid
        fi
        ;;
    all) show_all ;;
    s*) status ;;
    h*|--help) help ;;
    "") tobar ;;
    *) help ;;
esac

# Status bar click handlers (dwmblocks)
case $BLOCK_BUTTON in
    1) notify-send -t 60000 -i "$grid_file" "Supervolcano Monitor" "$(status)" ;;
    2) update ;;
    3) show_grid ;;
    4) notify-send -t 60000 -i "$cache/panel_yellowstone.png" "Yellowstone" "24hr Seismogram" ;;
    5) notify-send -t 60000 -i "$cache/panel_taupo.png" "Taupo" "Ruapehu North Webcam" ;;
    6) setsid -f "$TERMINAL" -e "$EDITOR" "$0" ;;
esac
