#!/usr/bin/env bash

cd "$(dirname "$0")"
work_dir="$( pwd -P )"

MISSION="${1:-PlanetiQ}"  # PlanetiQ | Spire
ENV="${2:-nccf}"          # rosdc | nccf | rhw1271

if [[ "$MISSION" != "PlanetiQ" && "$MISSION" != "Spire" ]]; then
    echo "ERROR: Unknown mission '$MISSION'"
    echo "Usage: $0 [PlanetiQ|Spire] [rosdc|nccf|rhw1271]"
    exit 1
fi

if [[ "$ENV" == "rosdc" ]]; then
    BASE="/data3/xinjiaz/data_GPSRO/ROSW/${MISSION}/p05_podTec"
    start_day='2026-05-18'
    MODE="realtime"
    MODE="historical"

elif [[ "$ENV" == "nccf" ]]; then
    BASE="/mnt/uvol0/jun.zhou/data_GPSRO/ROSW/${MISSION}/p05_podTec"  ## on dev0
    BASE="/mnt/uvol0/xinjia.zhou/data_GPSRO/ROSW/${MISSION}/p05_podTec" ## on dev1
    BASE="/data2/jzhou128/data_GPSRO/ROSW/planetiqrt/p05_podTec_nccf"
    start_day='2026-05-17'
    start_day='2026-05-18'
    MODE="realtime"
    MODE="historical"

elif [[ "$ENV" == "rhw1271" ]]; then
    BASE="/data3/xinjiaz/data_GPSRO/ROSW/${MISSION}/p05_podTec"
    start_day='2026-02-15'
    MODE="historical"
    MODE="realtime"
else
    echo "ERROR: Unknown argument '$ENV'"
    echo "Usage: $0 [PlanetiQ|Spire] [rosdc|nccf|rhw1271]"
    exit 1
fi

LOG="${work_dir}/count_L1B_TEC_30min_${MISSION,,}_${ENV}.log"
step=1800   # 30 minutes


# ============================================================
# L1B TEC availability monitoring
# ============================================================

PRODUCT="L1B_TEC"

SNS_REGION="us-east-1"
SNS_TOPIC_ARN="arn:aws:sns:us-east-1:190556942226:gitLab-ssbox-gnssro"

ALERT_THRESHOLD=7200       # Alert when no new file for over 2 hours

SNS_LOG_DIR="${work_dir}/sns_log"
mkdir -p "$SNS_LOG_DIR"

LAST_SEEN_FILE="${SNS_LOG_DIR}/last_seen_${MISSION,,}_${ENV}_${PRODUCT}.state"
ALERT_STATE_FILE="${SNS_LOG_DIR}/alert_${MISSION,,}_${ENV}_${PRODUCT}.state"
OUTAGE_START_FILE="${SNS_LOG_DIR}/outage_start_${MISSION,,}_${ENV}_${PRODUCT}.state"
ALERT_LOG="${SNS_LOG_DIR}/alert_${MISSION,,}_${ENV}_${PRODUCT}.log"


send_sns_alert() {
    local subject="$1"
    local message="$2"

    aws sns publish \
        --region "$SNS_REGION" \
        --topic-arn "$SNS_TOPIC_ARN" \
        --subject "$subject" \
        --message "$message"
}


##---------------
if [ "$MODE" = "historical" ]; then

    ## Find first day
#    start_day=$(ls -d ${BASE}/20??-??-?? 2>/dev/null | sort | head -n1 | xargs basename)
    start_epoch=$(date -u -d "${start_day} 00:00:00" +%s)

    # end of window = Top of current 30min (UTC)
    now_epoch=$(date -u +%s)
    end_epoch=$(( (now_epoch / 1800) * 1800 ))

    echo "INFO: scanning from ${start_day} to present (UTC)"
    echo "        UTC,                   ET,          GN04,  GN05,    Total" > "$LOG"

##---------------
else
##---------------
    number=48
    number=1   # <-- default. 1 for last 30 min, 2 for last 1 hour, etc.

    # end of window = Top of current 30min (UTC)
    now_epoch=$(date -u +%s)
    end_epoch=$(( (now_epoch / 1800) * 1800 ))

    # start of window = N steps before end_epoch
    start_epoch=$((end_epoch - step*number))
##---------------
fi


# ============================================================
# Load persistent last-seen time
# ============================================================

latest_seen=0

if [[ -s "$LAST_SEEN_FILE" ]]; then
    saved_epoch=$(cat "$LAST_SEEN_FILE")

    if [[ "$saved_epoch" =~ ^[0-9]+$ ]]; then
        latest_seen=$saved_epoch
    fi
fi

if (( latest_seen == 0 )); then
    # Give a newly created monitor a full two-hour grace period.
    latest_seen=$now_epoch
fi


current=$start_epoch

while [ "$current" -lt "$end_epoch" ]; do
    next=$((current + step))

#    --- starting time ---
#    hour_lt_str=$(date -d "@$current" "+%Y-%m-%d %H:%M:%S")
#    hour_str=$(date -u -d "@$current" "+%Y-%m-%d %H:%M:%S")

#    --- ending time ---
    hour_lt_str=$(date -d "@$next" "+%Y-%m-%d %H:%M:%S")
    hour_str=$(date -u -d "@$next" "+%Y-%m-%d %H:%M:%S")

    day1=$(date -u -d "@$((current - 3600))" "+%Y-%m-%d")
    day2=$(date -u -d "@$next" "+%Y-%m-%d")

    GN04=0; GN05=0

    days=("$day1")
    [ "$day1" != "$day2" ] && days+=("$day2")

    for day in "${days[@]}"; do
        day_dir="$BASE/$day"
        [ -d "$day_dir" ] || continue

        echo "day_dir: ${day_dir}" $(date)

        while IFS= read -r f; do
            m=$(stat -c %Y "$f" 2>/dev/null) || continue

            # Update the latest arrival time using the same local scan.
            if (( m <= now_epoch && m > latest_seen )); then
                latest_seen=$m
            fi

            if [ "$m" -ge "$current" ] && [ "$m" -lt "$next" ]; then
                filename="${f##*/}"
                # Match the satellite identifier as a filename token.
                if [[ "$filename" =~ (^|_)GN04(_|\.) ]]; then
                    ((GN04++))
                elif [[ "$filename" =~ (^|_)GN05(_|\.) ]]; then
                    ((GN05++))
                fi
            fi

        done < <(find "$day_dir" -type f -name "*.nc" 2>/dev/null)
    done

    total=$((GN04 + GN05))
    printf "%s, %s, %5d, %5d, %6d\n" \
        "$hour_str" "$hour_lt_str" "$GN04" "$GN05" "$total" >> "$LOG"

    current=$next
done


# ============================================================
# Save the updated last-seen time atomically
# ============================================================

tmp_state="${LAST_SEEN_FILE}.tmp.$$"

printf '%s\n' "$latest_seen" > "$tmp_state"
mv "$tmp_state" "$LAST_SEEN_FILE"


# ============================================================
# Evaluate the file-arrival gap
# ============================================================

monitor_epoch=$(date -u +%s)
gap_seconds=$((monitor_epoch - latest_seen))

if (( gap_seconds < 0 )); then
    gap_seconds=0
fi

gap_minutes=$((gap_seconds / 60))

last_seen_utc=$(date -u -d "@$latest_seen" "+%Y-%m-%d %H:%M:%S UTC")
last_seen_et=$(date -d "@$latest_seen" "+%Y-%m-%d %H:%M:%S %Z")

previous_alert=""

if [[ -s "$ALERT_STATE_FILE" ]]; then
    previous_alert=$(cat "$ALERT_STATE_FILE")
fi


# ============================================================
# Send gap alert or recovery email
# ============================================================

TEST_SEND=false  ## operational mode
#TEST_SEND=true     ## testing mode

echo "[$(date '+%Y-%m-%d %H:%M:%S')] TEST_SEND=${TEST_SEND}, gap=${gap_minutes} minutes" \
    >> "$ALERT_LOG"

if (( gap_seconds > ALERT_THRESHOLD )) || [[ "$TEST_SEND" == true ]]; then

    # Testing mode sends every run.
    # Operational mode sends once while the outage remains active.
    if [[ "$previous_alert" != "active" ]] || [[ "$TEST_SEND" == true ]]; then

        if [[ "$TEST_SEND" == true ]]; then
            subject="TEST: ${MISSION} ${PRODUCT} availability monitor"
        else
            subject="[ALERT] ${MISSION} ${PRODUCT}: no new files >2 hr"
        fi

        message="${MISSION} ${PRODUCT} data availability report

Test mode: ${TEST_SEND}
Mission: ${MISSION}
Product: ${PRODUCT}
Environment: ${ENV}

Last file arrival UTC: ${last_seen_utc}
Last file arrival ET: ${last_seen_et}
Current data gap: ${gap_minutes} minutes
Alert threshold: over 2 hours

Detected: $(date -u '+%Y-%m-%d %H:%M:%S UTC')
Host: $(hostname -s)
Monitor: $(basename "$0")

Local data location:
${BASE}

Please check the ${MISSION} ${PRODUCT} processing and data-delivery system."

        if send_sns_alert "$subject" "$message" >> "$ALERT_LOG" 2>&1; then

            # Do not change operational state during testing.
            if [[ "$TEST_SEND" != true ]]; then
                printf '%s\n' "active" > "$ALERT_STATE_FILE"

                # Save the time of the last file before the outage.
                printf '%s\n' "$latest_seen" > "$OUTAGE_START_FILE"
            fi

            echo "[$(date '+%Y-%m-%d %H:%M:%S')] SNS report sent; test=${TEST_SEND}; gap=${gap_minutes} minutes" \
                >> "$ALERT_LOG"
        else
            sns_status=$?

            echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: SNS report failed; exit=${sns_status}; test=${TEST_SEND}; gap=${gap_minutes} minutes" \
                >> "$ALERT_LOG"
        fi

    else
        echo "[$(date '+%Y-%m-%d %H:%M:%S')] Outage unchanged; gap=${gap_minutes} minutes" \
            >> "$ALERT_LOG"
    fi

else

    echo "[$(date '+%Y-%m-%d %H:%M:%S')] ${MISSION} ${PRODUCT} is OK; gap=${gap_minutes} minutes" \
        >> "$ALERT_LOG"

    # Send one recovery email only after a real operational alert.
    if [[ "$previous_alert" == "active" ]]; then

        # Calculate total missing-data duration.
        outage_start=0
        outage_seconds=0
        outage_minutes=0

        if [[ -s "$OUTAGE_START_FILE" ]]; then
            saved_outage_start=$(cat "$OUTAGE_START_FILE")

            if [[ "$saved_outage_start" =~ ^[0-9]+$ ]]; then
                outage_start=$saved_outage_start
                outage_seconds=$((latest_seen - outage_start))

                if (( outage_seconds < 0 )); then
                    outage_seconds=0
                fi

                outage_minutes=$((outage_seconds / 60))
            fi
        fi

        # Format the last-file time before the outage.
        if (( outage_start > 0 )); then
            outage_start_utc=$(date -u -d "@$outage_start" "+%Y-%m-%d %H:%M:%S UTC")
            outage_start_et=$(date -d "@$outage_start" "+%Y-%m-%d %H:%M:%S %Z")
        else
            outage_start_utc="unknown"
            outage_start_et="unknown"
        fi

        subject="[RECOVERY] ${MISSION} ${PRODUCT}: file delivery resumed"

        message="${MISSION} ${PRODUCT} data availability recovery

Mission: ${MISSION}
Product: ${PRODUCT}
Environment: ${ENV}

Last file before outage UTC: ${outage_start_utc}
Last file before outage ET: ${outage_start_et}

Latest file arrival UTC: ${last_seen_utc}
Latest file arrival ET: ${last_seen_et}

Missing data duration: ${outage_minutes} minutes
Current data gap: ${gap_minutes} minutes

Recovered: $(date -u '+%Y-%m-%d %H:%M:%S UTC')
Host: $(hostname -s)
Monitor: $(basename "$0")

Local data location:
${BASE}/

New ${MISSION} ${PRODUCT} files are arriving again."

        if send_sns_alert "$subject" "$message" >> "$ALERT_LOG" 2>&1; then
            rm -f "$ALERT_STATE_FILE" "$OUTAGE_START_FILE"

            echo "[$(date '+%Y-%m-%d %H:%M:%S')] RECOVERY email sent; missing duration=${outage_minutes} minutes" \
                >> "$ALERT_LOG"
        else
            echo "[$(date '+%Y-%m-%d %H:%M:%S')] ERROR: SNS recovery email failed; missing duration=${outage_minutes} minutes" \
                >> "$ALERT_LOG"
        fi
    fi
fi


echo "LOG: ${LOG}"
