#!/bin/bash
# ZFS Transfer Log Analyzer v7 (Added BUFFERED status)

export LC_NUMERIC=C

if [[ -z "$1" ]]; then
    echo "Usage: $0 <transfer_log_file>"
    exit 1
fi

LOGFILE="$1"
SUMMARY_MODE="${2:-}"

# --- Functions ---

format_bytes() {
    local bytes=${1%.*}
    if [[ -z "$bytes" || "$bytes" -eq 0 ]]; then echo "0"; return; fi
    numfmt --to=iec --format="%.2f" "$bytes" 2>/dev/null | sed 's/i//g'
}

format_speed_live() {
    local bps=$1
    if [[ $bps -eq 0 ]]; then
        echo "(stalled)"
    else
        local val=$(numfmt --to=iec "$bps" 2>/dev/null | sed 's/i//g')
        echo "($val /s)"
    fi
}

parse_duration() {
    local sec=${1%.*}
    if [[ $sec -ge 60 ]]; then
        printf "~%dm %ds" $((sec/60)) $((sec%60))
    else
        printf "%ds" "$sec"
    fi
}

# --- Parsing ---

SRC=$(head -n1 "$LOGFILE" | cut -d'>' -f1 | sed 's/->.*//;s/-$//')
DST=$(head -n1 "$LOGFILE" | cut -d'>' -f2)

# Визначаємо загальний час з початку логу
FIRST_LOG_TIME=$(grep -m1 "^[0-9][0-9]:[0-9][0-9]:[0-9][0-9]" "$LOGFILE" | awk '{print $1}')
LAST_LOG_TIME=$(grep "^[0-9][0-9]:[0-9][0-9]:[0-9][0-9]" "$LOGFILE" | tail -n1 | awk '{print $1}')

if [[ -n "$FIRST_LOG_TIME" && -n "$LAST_LOG_TIME" ]]; then
    T1=$(date -d "$FIRST_LOG_TIME" +%s 2>/dev/null)
    T2=$(date -d "$LAST_LOG_TIME" +%s 2>/dev/null)
    ELAPSED_SEC=$((T2 - T1))
    ELAPSED_STR=$(parse_duration "$ELAPSED_SEC")
else
    ELAPSED_STR="Calculating..."
fi

LAST_LINE=$(tail -n1 "$LOGFILE")
if [[ "$LAST_LINE" =~ received.*stream ]]; then
    STATUS="COMPLETED"
    ICON="✓"
else
    STATUS="IN PROGRESS"
    ICON="⏳"
fi

RESUME_MODE=false
if grep -q "^resume token contents:" "$LOGFILE" && ! grep -q "^do sync" "$LOGFILE"; then
    RESUME_MODE=true
fi

declare -a SNAP_NAMES
declare -a SNAP_SIZES
declare -a SNAP_STATUS 
declare -a SNAP_REAL_TIME
declare -a SNAP_REAL_SPEED

# Parse snap names and sizes from full/incremental lines
# full:        $1=full        $2=ds@snap  $3=size
# incremental: $1=incremental $2=@from    $3=ds@snap  $4=size
while IFS= read -r line; do
    type=$(echo "$line" | awk '{print $1}')
    if [[ "$type" == "full" ]]; then
        s_name=$(echo "$line" | awk '{print $2}' | cut -d'@' -f2)
        s_size=$(echo "$line" | awk '{print $3}')
    else
        s_name=$(echo "$line" | awk '{print $3}' | cut -d'@' -f2)
        s_size=$(echo "$line" | awk '{print $4}')
    fi
    SNAP_NAMES+=("$s_name")
    SNAP_SIZES+=("${s_size:-0}")
    SNAP_STATUS+=("PENDING")
done < <(grep -E "^(full|incremental)" "$LOGFILE")

# Total plan size from the single ^size line at end of stream
_size_line=$(grep "^size" "$LOGFILE" | tail -1)
STREAM_TOTAL_SIZE=$(echo "$_size_line" | awk '{print $2}')

TOTAL_PLAN_SIZE=0
TOTAL_TRANSFERRED=0
SPEED_SUM=0
SPEED_COUNT=0
SPEED_MIN=999999999
SPEED_MAX=0

# Спочатку маркуємо всі DONE (які мають received)
COMPLETED_LOGS=$(grep "^received.*stream in" "$LOGFILE")
COMPLETED_IDX=0

while read -r line; do
    if [[ -z "$line" ]]; then continue; fi
    time_sec=$(echo "$line" | sed -n 's/.*in \([0-9.]*\) seconds.*/\1/p')
    speed_raw=$(echo "$line" | sed -n 's/.*(\([0-9.]*\).*/\1/p')
    speed_val=$(echo "$speed_raw" | sed 's/[^0-9.]//g')
    
    if [[ $COMPLETED_IDX -lt ${#SNAP_NAMES[@]} ]]; then
        SNAP_STATUS[$COMPLETED_IDX]="DONE"
        SNAP_REAL_TIME[$COMPLETED_IDX]="$time_sec"
        SNAP_REAL_SPEED[$COMPLETED_IDX]="$speed_raw"
        
        if (( $(echo "$speed_val < $SPEED_MIN" | bc -l) )); then SPEED_MIN=$speed_val; fi
        if (( $(echo "$speed_val > $SPEED_MAX" | bc -l) )); then SPEED_MAX=$speed_val; fi
        SPEED_SUM=$(echo "$SPEED_SUM + $speed_val" | bc -l)
        SPEED_COUNT=$((SPEED_COUNT + 1))
        ((COMPLETED_IDX++))
    fi
done <<< "$COMPLETED_LOGS"

for size in "${SNAP_SIZES[@]}"; do
    TOTAL_PLAN_SIZE=$(echo "$TOTAL_PLAN_SIZE + $size" | bc)
done
if [[ -n "${STREAM_TOTAL_SIZE:-}" && "$STREAM_TOTAL_SIZE" -gt 0 ]]; then
    TOTAL_PLAN_SIZE=$STREAM_TOTAL_SIZE
fi
# Override with stream total if available (more accurate — accounts for compression etc.)
if [[ -n "${STREAM_TOTAL_SIZE:-}" && "$STREAM_TOTAL_SIZE" -gt 0 ]]; then
    TOTAL_PLAN_SIZE=$STREAM_TOTAL_SIZE
fi

# Визначаємо ACTIVE snapshot (останній з progress lines)
ACTIVE_IDX=-1
if [[ "$STATUS" == "IN PROGRESS" ]]; then
    LAST_PROGRESS_LINE=$(grep "^[0-9][0-9]:[0-9][0-9]:[0-9][0-9]" "$LOGFILE" | tail -n1)
    if [[ -n "$LAST_PROGRESS_LINE" ]]; then
        ACTIVE_CURRENT_BYTES=$(echo "$LAST_PROGRESS_LINE" | awk '{print $2}')
        short_snap_name=$(echo "$LAST_PROGRESS_LINE" | awk '{print $3}' | cut -d'@' -f2)
        for i in "${!SNAP_NAMES[@]}"; do
            if [[ "${SNAP_NAMES[$i]}" == "$short_snap_name" ]]; then
                SNAP_STATUS[$i]="ACTIVE"
                ACTIVE_IDX=$i
                break
            fi
        done
    fi
fi

# Тепер маркуємо BUFFERED (send завершив, але receive ще не підтвердив)
# BUFFERED можуть бути тільки між останнім DONE та ACTIVE
LAST_DONE_IDX=-1
for i in "${!SNAP_NAMES[@]}"; do
    if [[ "${SNAP_STATUS[$i]}" == "DONE" ]]; then
        LAST_DONE_IDX=$i
    fi
done

# Якщо є ACTIVE, то між LAST_DONE і ACTIVE мають бути BUFFERED
if [[ $ACTIVE_IDX -ge 0 && $LAST_DONE_IDX -ge 0 ]]; then
    for ((i = LAST_DONE_IDX + 1; i < ACTIVE_IDX; i++)); do
        if [[ "${SNAP_STATUS[$i]}" == "PENDING" ]]; then
            # Перевіряємо чи є progress lines
            has_progress=$(grep -c "@${SNAP_NAMES[$i]}" "$LOGFILE" 2>/dev/null || echo 0)
            if [[ $has_progress -gt 0 ]]; then
                SNAP_STATUS[$i]="BUFFERED"
            fi
        fi
    done
fi

# Обчислюємо TOTAL_TRANSFERRED
for i in "${!SNAP_NAMES[@]}"; do
    if [[ "${SNAP_STATUS[$i]}" == "DONE" ]]; then
        TOTAL_TRANSFERRED=$(echo "$TOTAL_TRANSFERRED + ${SNAP_SIZES[$i]}" | bc)
    elif [[ "${SNAP_STATUS[$i]}" == "BUFFERED" ]]; then
        # Для buffered - додаємо повний розмір (send завершив)
        TOTAL_TRANSFERRED=$(echo "$TOTAL_TRANSFERRED + ${SNAP_SIZES[$i]}" | bc)
    elif [[ "${SNAP_STATUS[$i]}" == "ACTIVE" ]]; then
        TOTAL_TRANSFERRED=$(echo "$TOTAL_TRANSFERRED + $ACTIVE_CURRENT_BYTES" | bc)
    fi
done

# --- Output ---

if [[ "$SUMMARY_MODE" == "--summary" ]]; then
    if [[ "$TOTAL_PLAN_SIZE" -eq 0 ]]; then
        echo "0 bytes (already synced)"
    elif [[ $SPEED_COUNT -gt 0 ]]; then
        AVG_SPEED=$(echo "scale=2; $SPEED_SUM / $SPEED_COUNT" | bc -l)
        echo "$(format_bytes $TOTAL_PLAN_SIZE) in $ELAPSED_STR (avg ${AVG_SPEED}M/s)"
    else
        echo "$(format_bytes $TOTAL_PLAN_SIZE) in $ELAPSED_STR"
    fi
    exit 0
fi

echo "=== ZFS Transfer Summary ==="
echo "Source:      $SRC"
echo "Destination: $DST"
echo "Status: $ICON $STATUS$([[ "$RESUME_MODE" == "true" ]] && echo " (resume)")"
[[ "$RESUME_MODE" == "true" ]] && echo "Note: Resuming interrupted transfer — only current snapshot visible"
echo ""

# Pre-calculate live speed for ETA fallback
LIVE_BPS=0
if [[ $ACTIVE_IDX -ge 0 ]]; then
    _raw=$(grep "^[0-9].*${SNAP_NAMES[$ACTIVE_IDX]}" "$LOGFILE" | tail -n 10)
    _t1=$(date -d "$(echo "$_raw" | head -n1 | awk '{print $1}')" +%s 2>/dev/null)
    _b1=$(echo "$_raw" | head -n1 | awk '{print $2}')
    _t2=$(date -d "$(echo "$_raw" | tail -n1 | awk '{print $1}')" +%s 2>/dev/null)
    _b2=$(echo "$_raw" | tail -n1 | awk '{print $2}')
    _dt=$(( ${_t2:-0} - ${_t1:-0} ))
    _db=$(( ${_b2:-0} - ${_b1:-0} ))
    [[ $_dt -gt 0 ]] && LIVE_BPS=$(( _db / _dt ))
fi

if [[ "$STATUS" == "IN PROGRESS" ]]; then
    PCT=$(echo "$TOTAL_TRANSFERRED * 100 / $TOTAL_PLAN_SIZE" | bc)
    REMAINING_BYTES=$(echo "$TOTAL_PLAN_SIZE - $TOTAL_TRANSFERRED" | bc)
    if (( $(echo "$SPEED_SUM > 0" | bc -l) )); then
         AVG_SPEED_VAL=$(echo "scale=2; $SPEED_SUM / $SPEED_COUNT" | bc -l)
         BYTES_PER_SEC=$(echo "$AVG_SPEED_VAL * 1048576" | bc)
         if (( $(echo "$BYTES_PER_SEC > 0" | bc -l) )); then
            ETA_SEC=$(echo "$REMAINING_BYTES / $BYTES_PER_SEC" | bc)
            ETA_STR=$(parse_duration "$ETA_SEC")
         else ETA_STR="Unknown"; fi
    elif [[ $LIVE_BPS -gt 0 ]]; then
        ETA_SEC=$(( REMAINING_BYTES / LIVE_BPS ))
        ETA_STR=$(parse_duration "$ETA_SEC")
    else ETA_STR="Calculating..."; fi
    
    echo "Overall Progress: $(format_bytes $TOTAL_TRANSFERRED) / $(format_bytes $TOTAL_PLAN_SIZE) ($PCT%)"
    echo "Elapsed: $ELAPSED_STR"
    echo "ETA: $ETA_STR (based on avg speed)"
    echo ""
else
    # Для COMPLETED статусу також виводимо підсумок часу
    echo "Overall Progress: $(format_bytes $TOTAL_PLAN_SIZE) / $(format_bytes $TOTAL_PLAN_SIZE) (100%)"
    echo "Total Time: $ELAPSED_STR"
    echo ""
fi

if [[ $SPEED_COUNT -gt 0 ]]; then
    AVG_SPEED=$(echo "scale=2; $SPEED_SUM / $SPEED_COUNT" | bc -l)
    echo "Speed statistics:"
    echo "  Min: ${SPEED_MIN}M/s"
    echo "  Avg: ${AVG_SPEED}M/s"
    echo "  Max: ${SPEED_MAX}M/s"
    echo ""
fi

if [[ "$RESUME_MODE" != "true" ]]; then
echo "=== Snapshot Details ==="
for i in "${!SNAP_NAMES[@]}"; do
    s_name="${SNAP_NAMES[$i]}"
    s_size=$(format_bytes "${SNAP_SIZES[$i]}")
    if [[ "${SNAP_STATUS[$i]}" == "DONE" ]]; then
        if [[ "$STATUS" == "COMPLETED" ]]; then
            printf "%-30s %s in %ss (%sM/s)\n" "$s_name:" "$s_size" "$(printf "%.0f" "${SNAP_REAL_TIME[$i]}")" "${SNAP_REAL_SPEED[$i]}"
        else
            printf "%-30s %s ✓ in %ss (%sM/s)\n" "$s_name:" "$s_size" "$(printf "%.0f" "${SNAP_REAL_TIME[$i]}")" "${SNAP_REAL_SPEED[$i]}"
        fi
    elif [[ "${SNAP_STATUS[$i]}" == "BUFFERED" ]]; then
        printf "%-30s %s ⧗ (pending finish)\n" "$s_name:" "$s_size"
    elif [[ "${SNAP_STATUS[$i]}" == "ACTIVE" ]]; then
        printf "%-30s %s ⏳ (in progress)\n" "$s_name:" "$s_size"
    else
        printf "%-30s %s ⋯ (pending)\n" "$s_name:" "$s_size"
    fi
done
fi

if [[ "$STATUS" == "IN PROGRESS" && $ACTIVE_IDX -ge 0 ]]; then
    echo ""
    echo "=== Current Snapshot (LIVE) ==="
    TARGET_SIZE=${SNAP_SIZES[$ACTIVE_IDX]}
    CUR_PCT=$(echo "$ACTIVE_CURRENT_BYTES * 100 / $TARGET_SIZE" | bc)
    
    RAW_LINES=$(grep "^[0-9].*${SNAP_NAMES[$ACTIVE_IDX]}" "$LOGFILE" | tail -n 19)
    LAST_LINE_DATA=$(echo "$RAW_LINES" | tail -n1)
    
    T_S=$(date -d "$(echo "$RAW_LINES" | head -n1 | awk '{print $1}')" +%s 2>/dev/null)
    B_S=$(echo "$RAW_LINES" | head -n1 | awk '{print $2}')
    T_E=$(date -d "$(echo "$LAST_LINE_DATA" | awk '{print $1}')" +%s 2>/dev/null)
    B_E=$(echo "$LAST_LINE_DATA" | awk '{print $2}')
    D_T=$((T_E - T_S)); D_B=$((B_E - B_S))
    
    if [[ $D_T -gt 0 ]]; then
        L_BPS=$((D_B / D_T))
        L_MBPS=$(echo "scale=2; $L_BPS / 1048576" | bc -l)
        L_ETA=$(parse_duration $(( (TARGET_SIZE - B_E) / L_BPS )))
    else L_MBPS="0.00"; L_ETA="Stalled"; fi

    echo "Snapshot: ${SNAP_NAMES[$ACTIVE_IDX]}"
    echo "Progress: $(format_bytes $ACTIVE_CURRENT_BYTES) / $(format_bytes $TARGET_SIZE) ($CUR_PCT%)"
    echo "Speed: ${L_MBPS}M/s (last ${D_T}s)"
    echo "Remaining: $(format_bytes $((TARGET_SIZE - ACTIVE_CURRENT_BYTES)))"
    echo "ETA: $L_ETA"
    echo ""
    echo "Recent progress:"
    
    RECENT_CHUNK=$(echo "$RAW_LINES" | tail -n 17)
    PREV_T=""; PREV_B=0
    while read -r line; do
        curr_t=$(echo "$line" | awk '{print $1}')
        curr_b=$(echo "$line" | awk '{print $2}')
        if [[ -n "$PREV_T" ]]; then
            t1=$(date -d "$PREV_T" +%s 2>/dev/null); t2=$(date -d "$curr_t" +%s 2>/dev/null)
            dt=$((t2 - t1)); db=$((curr_b - PREV_B))
            if [[ $dt -gt 0 ]]; then
                s_str=$(format_speed_live $((db / dt)))
            else s_str="(-)"; fi
            echo "  $curr_t  $(format_bytes $curr_b)  $s_str"
        fi
        PREV_T="$curr_t"; PREV_B="$curr_b"
    done <<< "$RECENT_CHUNK"
fi
