#!/bin/bash 

# ================= 配置参数 =================
MonitorIP="192.168.5.1"
DelayBetweenRetries=30
RetryTimes=3
CheckInterval=60

# 日志配置
# LogFile="/home/mickey/APP/sh/server-monitor/log/server_monitor.log"
# LOG_DIR=$(dirname "$LogFile")
# mkdir -p "$LOG_DIR"

MailTo="1975392257@qq.com"
Hostname=$(hostname)
NetInterface="enp2s0"

# 状态变量
LastIPv6s=()
PowerLossDetected=0
PowerLossTime=""

# 心跳配置
HEARTBEAT_HOURS=("00" "06" "12" "18")
LAST_HEARTBEAT_TAG="" 

# ================= 辅助函数：获取当前 IPv6 =================
get_current_ipv6s() {
    ip -6 addr show dev "$NetInterface" scope global | awk '/inet6/ {
        ip=$2; sub(/\/[0-9]+$/,"",ip);
        if (ip ~ /^f[cde]/) next;
        if ($0 ~ /deprecated/) next;
        if ($0 ~ /temporary/) next;
        print ip
    }' | sort
}

# 发送邮件的通用函数
send_mail() {
    local subject="$1"
    local content="$2"
    {
        echo "To: $MailTo"
        echo "Subject: $subject"
        echo "Date: $(date -R)"
        echo "Content-Type: text/plain; charset=UTF-8"
        echo
        echo "$content"
    } | msmtp -a default "$MailTo"
}

echo "[$(date)] Starting Server Monitor on $Hostname..."

# ==========================================
# [启动初始化] 第一次运行的逻辑
# ==========================================
mapfile -t LastIPv6s < <(get_current_ipv6s)

if [ ${#LastIPv6s[@]} -gt 0 ]; then
    # 场景1：启动时直接获取到了 IP -> 发送“首次获取”邮件
    now_time=$(date "+%F %T")
    
    # 将数组转为字符串显示
    current_ip_str=$(printf "%s\n" "${LastIPv6s[@]}")
    
    msg="[$now_time] 脚本启动，首次获取到 IPv6 地址："$'\n'"$current_ip_str"
    echo "$msg" | tee -a "$LogFile"
    send_mail "IPv6 地址首次获取" "$msg"
else
    # 场景2：启动时没网 -> 记录日志，不做处理，等待循环中获取
    echo "[Init] 启动时暂无 IPv6 地址，等待获取..." | tee -a "$LogFile"
fi

# ================= 主循环 =================
while true; do
    now_hour=$(date +%H)
    now_date=$(date +%F)
    now_time=$(date "+%F %T")

    # ==========================================
    # 1. 路由器 Ping 检测
    # ==========================================
    failure_count=0
    for ((i=1; i<=RetryTimes; i++)); do
        if ping -c 1 -W 3 "$MonitorIP" &> /dev/null; then
            failure_count=0
            break
        else
            if [ "$i" -eq "$RetryTimes" ]; then
                 echo "[$now_time] Ping failed #$i" | tee -a "$LogFile"
            fi
            ((failure_count++))
            sleep "$DelayBetweenRetries"
        fi
    done

    if [ "$failure_count" -ge "$RetryTimes" ]; then
        if [ "$PowerLossDetected" -eq 0 ]; then
            PowerLossDetected=1
            PowerLossTime="$now_time"
            echo "[$now_time] 路由器断电（Ping 不通），记录断电时间，已安排5分钟后关机。" | tee -a "$LogFile"
            sudo /usr/sbin/shutdown -h +5 "路由器断电，系统将在5分钟后自动关机"
        fi
    else
        if [ "$PowerLossDetected" -eq 1 ]; then
            echo "[$now_time] 网络恢复，发送断电和恢复邮件。" | tee -a "$LogFile"
            msg_off="路由器断电事件通知：断电时间为 $PowerLossTime 。"
            msg_on="路由器网络已恢复，恢复时间为 $now_time ，系统关机任务已取消。"
            send_mail "路由器断电与恢复通知" "$msg_off"$'\n'"--------------------------------"$'\n'"$msg_on"
            sudo /usr/sbin/shutdown -c
            PowerLossDetected=0
            PowerLossTime=""
        fi
    fi

    # ==========================================
    # 2. 心跳邮件
    # ==========================================
    current_tag="${now_date}_${now_hour}"
    should_send=0
    for h in "${HEARTBEAT_HOURS[@]}"; do
        if [[ "$now_hour" == "$h" ]]; then should_send=1; break; fi
    done
    if [[ "$should_send" -eq 1 && "$LAST_HEARTBEAT_TAG" != "$current_tag" ]]; then
        msg="[$now_time] 服务器 $Hostname 正常运行，未断电。"
        echo "$msg" | tee -a "$LogFile"
        send_mail "服务器运行状态" "$msg"
        LAST_HEARTBEAT_TAG="$current_tag"
    fi

    # ==========================================
    # 3. IPv6 地址变化检测
    # ==========================================
    
    # 3.1 获取当前 IP
    mapfile -t AllIPv6s < <(get_current_ipv6s)

    # 3.2 【防空逻辑】
    # 如果当前没有 IP (正在重拨)，什么都不做，直接跳过。
    # 这样旧 IP (LastIPv6s) 就会保留在内存里，等待新 IP 出现。
    if [ ${#AllIPv6s[@]} -eq 0 ]; then
        sleep "$CheckInterval"
        continue
    fi

    # 3.3 对比逻辑
    # 将数组转为字符串进行比较
    current_str=$(printf "%s\n" "${AllIPv6s[@]}")
    last_str=$(printf "%s\n" "${LastIPv6s[@]}")

    if [[ "$current_str" != "$last_str" ]]; then
        
        # 场景 A: 之前没有IP (Last为空)，现在突然有了 (从启动无网状态恢复)
        if [ ${#LastIPv6s[@]} -eq 0 ]; then
             msg="[$now_time] 检测到 IPv6 地址上线："$'\n'"$current_str"
             echo "$msg" | tee -a "$LogFile"
             send_mail "IPv6 地址首次获取" "$msg"
             
        # 场景 B: 之前有IP，现在变了 (正常变更)
        else
             # 构造你想要的 "旧 -> 新" 格式
             # 注意：如果有多个IP，这里会直接全部打印出来
             changes="$last_str"$'\n'"   ↓"$'\n'"$current_str"
             
             msg="[$now_time] 服务器 $Hostname IPv6 地址变更："$'\n'"$changes"
             echo "$msg" | tee -a "$LogFile"
             send_mail "IPv6 地址变更" "$msg"
        fi

        # 3.4 更新缓存
        LastIPv6s=("${AllIPv6s[@]}")
    fi

    sleep "$CheckInterval"
done
