#!/bin/bash
[ -z "$1" ] && exit 1
[ "$2" = "/dev/md8" -o "$2" = "/dev/md9" ] && exit 1
. /etc/profile >/dev/null

# 调试日志文件
HOTSPARE_DEBUG_LOG="/tmp/hotspare-debug.log"
echo "========== $(date) ==========" >> "$HOTSPARE_DEBUG_LOG"
echo "Args: $@" >> "$HOTSPARE_DEBUG_LOG"

# 日志函数：同时写 syslog 和文件
log_debug() {
    local msg="$1"
    logger -t "MDADM-MONITOR" "$msg"
    echo "[$(date '+%Y-%m-%d %H:%M:%S')] $msg" >> "$HOTSPARE_DEBUG_LOG"
}

# 内联 scripts 中所需变量，解除对 /etc/tos/scripts/scripts 的依赖
TOS_RAID_CORE=/dev/md9
TOS_RAID_SWAP=/dev/md8
TOS_DEFAULT_CONFIG=/etc/tos/conf/tos.ini
TOS_CORE_SIZE=$(iniparse -c -f $TOS_DEFAULT_CONFIG -s tos -k core_size)
TOS_SWAP_SIZE=$(iniparse -c -f $TOS_DEFAULT_CONFIG -s tos -k swap_size)
TOS_BOOT_SIZE=$(iniparse -c -f $TOS_DEFAULT_CONFIG -s tos -k boot_size)

buzzerpid=/var/run/warnning.pid
STORAGE_MANAGER_SOCK=/var/run/socks/storage.sock
buzzerexe=/etc/tos/scripts/warnning
buzzer_config=/etc/buzzer/buzzer_config.info
MNTOPTS=$MNTOPT_EXT4
CACHE_DEGRADED_FLAG_DIR="/tmp/cache_degraded"

# optimization sync speed limit
sysctl -w dev.raid.speed_limit_max=200000
sysctl -w dev.raid.speed_limit_min=100000

mkparted() {
    local blk=$1
    local offset=0
    local offend=0
    # parted -s $blk mktable gpt
    [ $? -ne 0 ] && return 1
    let offend=$offset+$TOS_BOOT_SIZE
    if [ ! -b ${blk}1 ];then
        parted -s $blk mkpart primary ext2 0% $offend
    fi
    let offset=$offend
    let offend=$offset+$TOS_CORE_SIZE
    if [ ! -b ${blk}2 ];then
        parted -s $blk mkpart primary ext2 $offset $offend
    fi
    let offset=$offend
    let offend=$offset+$TOS_SWAP_SIZE
    if [ ! -b ${blk}3 ];then
        parted -s $blk mkpart primary ext2 $offset $offend
    fi
    partprobe "${blk}"
    udevadm settle --timeout=10
    if [ ! -b ${blk}1 ] || [ ! -b ${blk}2 ] || [ ! -b ${blk}3 ];then
        sleep 2
        if [ ! -b ${blk}1 ] || [ ! -b ${blk}2 ] || [ ! -b ${blk}3 ];then
            logger -t "MDADM-MONITOR" "[hotspare]: mkparted [$blk] Error, can't get valid part(1-3)"
            return 1
        fi
    fi
    let offset=$offend
    parted -s $blk mkpart primary ext2 $offset 100%
    if [ $? -ne 0 ];then
        logger -t "MDADM-MONITOR" "[hotspare]: mkparted [$blk] Error, can't parted user partition"
        return 1
    fi
    partprobe "${blk}"
    udevadm settle --timeout=10
    sleep 1
    mdadm --zero-superblock "${blk}4"
    # init partition 1 ...
    # /etc/tos/scripts/initboot "$blk"
    return 0
}

hotspare() {
    local raid=$1
    local name=$(basename $raid)
    log_debug "[hotspare]: DEBUG ENTER - raid=$raid name=$name"

    local status=$(cat /sys/block/${name}/md/sync_action 2>/dev/null)
    log_debug "[hotspare]: raid ${name} initial sync_action [$status]"

    if [ "$status" = "reshape" ]; then
        # reshape 期间内核不允许 recovery 并行，热备盘无法激活
        # 不做等待，干净退出；reshape 完成后由 RebuildFinished 事件触发热备
        log_debug "[hotspare]: raid ${name} is reshaping, skip hot spare, wait for sync completion event"
        return
    fi

    local wait=5
    while [ $wait -gt 0 ]; do
        log_debug "[hotspare]: raid ${name} status [$status]"
        if [ "$status" = "idle" ]; then
            break
        fi
        let wait=wait-1
        [ $wait -eq 0 ] && exit 1
        sleep 1
        status=$(cat /sys/block/${name}/md/sync_action 2>/dev/null)
    done
    # 备份 hotspare.conf：ter_hotspare 会删除已选磁盘的配置条目并保存。
    # 若此后 reshape 启动导致 mdadm -a 失败，需从备份恢复条目，
    # 以便 RebuildFinished 事件再次触发热备时配置仍可用。
    cp /etc/tos/conf/hotspare.conf /tmp/hotspare.conf.bak 2>/dev/null
    local avadisk=$(ter_hotspare -r ${raid})
    avadisk=$(echo "$avadisk" | grep -o -E '\bsd[a-z]+\b')
    log_debug "[hotspare]: raid ${name} avadisk [$avadisk]"
    #fix Traid in ter_hotspare
    if [ "$avadisk" = "traid" ]; then
        log_debug "[hotspare]: DEBUG - avadisk is traid, returning"
        return
    fi

    [ -z "$avadisk" ] && exit 1
    local blk="/dev/$avadisk"
    [ ! -b "$blk" ] && exit 1
    log_debug "[hotspare]: DEBUG - blk=$blk, block device exists"

    # 检测热备盘与池的系统分区版本是否一致
    local blkname=$(basename $blk)
    log_debug "[hotspare]: DEBUG - blkname=$blkname"

    # 读取磁盘的分区信息
    log_debug "[hotspare]: DEBUG - checking partitions on $blk"
    local diskP2Size=0
    if [ -b ${blk}2 ]; then
        local diskP2Sectors=$(cat /sys/block/${blkname}/${blkname}2/size 2>/dev/null || echo 0)
        log_debug "[hotspare]: DEBUG - ${blk}2 exists, sectors=$diskP2Sectors"
        [ "$diskP2Sectors" -gt 0 ] && diskP2Size=$((diskP2Sectors * 512 / 1000000))
    else
        log_debug "[hotspare]: DEBUG - ${blk}2 does NOT exist"
    fi
    log_debug "[hotspare]: DEBUG - diskP2Size=${diskP2Size}MB"

    # 从池的一个成员盘获取池版本（p2 大小）
    local poolCoreSize=0
    log_debug "[hotspare]: DEBUG - checking pool members in /sys/block/$name/slaves/"
    local slave_list=$(ls /sys/block/$name/slaves/ 2>/dev/null)
    log_debug "[hotspare]: DEBUG - slave_list=$slave_list"

    for slave in $slave_list; do
        local memberDisk=$(echo $slave | sed 's/[0-9]*$//')
        log_debug "[hotspare]: DEBUG - checking slave=$slave memberDisk=$memberDisk"
        if [ -b /dev/${memberDisk}2 ]; then
            local memberSectors=$(cat /sys/block/${memberDisk}/${memberDisk}2/size 2>/dev/null || echo 0)
            log_debug "[hotspare]: DEBUG - /dev/${memberDisk}2 exists, sectors=$memberSectors"
            if [ "$memberSectors" -gt 0 ]; then
                poolCoreSize=$((memberSectors * 512 / 1000000))
                log_debug "[hotspare]: DEBUG - poolCoreSize=${poolCoreSize}MB from $memberDisk"
                break
            fi
        else
            log_debug "[hotspare]: DEBUG - /dev/${memberDisk}2 does NOT exist"
        fi
    done
    log_debug "[hotspare]: DEBUG - final poolCoreSize=${poolCoreSize}MB"

    # 版本检测逻辑
    log_debug "[hotspare]: DEBUG - version check: diskP2Size=$diskP2Size poolCoreSize=$poolCoreSize"
    if [ "$diskP2Size" -gt 0 ] && [ "$poolCoreSize" -gt 0 ] && [ "$diskP2Size" != "$poolCoreSize" ]; then
        log_debug "[hotspare]: DEBUG - VERSION MISMATCH detected, formatting to align"
        log_debug "[hotspare]: DEBUG - TOS_CORE_SIZE before=$TOS_CORE_SIZE"

        # 1. 从系统 RAID 移除
        log_debug "[hotspare]: DEBUG - step1: removing from system RAID"
        local fail_p2=$(mdadm --manage $TOS_RAID_CORE --fail ${blk}2 2>&1)
        log_debug "[hotspare]: mdadm fail p2: $fail_p2"
        local remove_p2=$(mdadm --manage $TOS_RAID_CORE --remove ${blk}2 2>&1)
        log_debug "[hotspare]: mdadm remove p2: $remove_p2"
        local fail_p3=$(mdadm --manage $TOS_RAID_SWAP --fail ${blk}3 2>&1)
        log_debug "[hotspare]: mdadm fail p3: $fail_p3"
        local remove_p3=$(mdadm --manage $TOS_RAID_SWAP --remove ${blk}3 2>&1)
        log_debug "[hotspare]: mdadm remove p3: $remove_p3"

        # 2. 清除 RAID 元数据
        log_debug "[hotspare]: DEBUG - step2: zero-superblock"
        local zero_p2=$(mdadm --zero-superblock ${blk}2 2>&1)
        log_debug "[hotspare]: zero-superblock p2: $zero_p2"
        local zero_p3=$(mdadm --zero-superblock ${blk}3 2>&1)
        log_debug "[hotspare]: zero-superblock p3: $zero_p3"

        # 3. 删除所有分区
        log_debug "[hotspare]: DEBUG - step3: deleting all partitions"
        for i in $(seq 1 9); do
            local rm_part=$(parted -s $blk rm $i 2>&1)
            log_debug "[hotspare]: parted rm $i: $rm_part"
        done

        # 4. 重建 GPT
        log_debug "[hotspare]: DEBUG - step4: recreating GPT table"
        local mktable_out=$(parted -s $blk mktable gpt 2>&1)
        log_debug "[hotspare]: parted mktable: $mktable_out"

        # 5. 覆盖 TOS_CORE_SIZE
        TOS_CORE_SIZE=$poolCoreSize
        log_debug "[hotspare]: DEBUG - TOS_CORE_SIZE after=$TOS_CORE_SIZE"

        # 验证分区状态
        log_debug "[hotspare]: DEBUG - verifying partition state after cleanup"
        local block_devs=$(ls -la ${blk}* 2>&1)
        log_debug "[hotspare]: block devices: $block_devs"
    else
        log_debug "[hotspare]: DEBUG - NO version mismatch detected"
        # 有分区且版本匹配或空白盘时，都用池实际大小覆盖配置值
        # 有分区场景：p4 偏移需与实际 p2/p3 位置一致，否则 parted 因重叠拒绝创建
        # 空白盘场景：创建的分区需与池其他成员大小一致
        if [ "$poolCoreSize" -gt 0 ]; then
            log_debug "[hotspare]: DEBUG - overriding TOS_CORE_SIZE from config ($TOS_CORE_SIZE) to pool value ($poolCoreSize)"
            TOS_CORE_SIZE=$poolCoreSize
        fi
    fi

    log_debug "[hotspare]: DEBUG - calling mkparted with TOS_CORE_SIZE=$TOS_CORE_SIZE"
    mkparted "$blk"
    local mkparted_rc=$?
    log_debug "[hotspare]: DEBUG - mkparted returned rc=$mkparted_rc"
    [ $mkparted_rc -ne 0 ] && exit 1

    log_debug "[hotspare]: raid ${name} parted [$blk]"
    log_debug "[hotspare]: DEBUG - checking partitions after mkparted"
    local block_devs_after=$(ls -la ${blk}* 2>&1)
    log_debug "[hotspare]: block devices after mkparted: $block_devs_after"

    if [ -b "${blk}2" -a -b "${blk}3" -a -b "${blk}4" ]; then
        log_debug "[hotspare]: DEBUG - all required partitions exist, proceeding to add to RAID"
        local diskname=$blk
        local tmpfile="/tmp/hotspare_${avadisk}"
        if [ -f $tmpfile ]; then
            diskname=$(cat $tmpfile)
            rm -f $tmpfile
        fi
        # mdadm -a /dev/md9 ${blk}2
        # mdadm -a /dev/md8 ${blk}3
        # 二次 reshape 检测：ter_hotspare 消费配置后到此处可能已过数秒，
        # reshape 可能在此期间启动。若 reshape 已开始，mdadm -a 必定失败且配置已被消费，
        # 必须从备份恢复配置，以便 RebuildFinished 事件再次触发时热备盘仍可用。
        local action_now=$(cat /sys/block/${name}/md/sync_action 2>/dev/null)
        if [ "$action_now" = "reshape" ]; then
            log_debug "[hotspare]: raid ${name} reshape started since ter_hotspare ran, restoring config and aborting"
            if [ -f /tmp/hotspare.conf.bak ]; then
                cp /tmp/hotspare.conf.bak /etc/tos/conf/hotspare.conf
                log_debug "[hotspare]: hotspare.conf restored from backup"
            fi
            rm -f /tmp/hotspare.conf.bak
            return
        fi
        rm -f /tmp/hotspare.conf.bak
        mdadm -a $raid ${blk}4
        #hotspare send mail
        local diskInfo=$(ter_disk_tool -blockdev $blk)
        local diskName=$(echo $diskInfo | jq -r .name)
        ter_msg_add -c storage -code notice_hotspare_enable -l info -s notification -k notice_hotspare_enable -o $diskName
        # stop the warnning
        close_buzzer
    fi
}

sync_finish() {
    local raid=$1
    local raidname=$(basename "$raid")
    local status=$(cat /sys/block/$raidname/md/degraded)
    local sort=${raidname:2}
    local fs=$(blkid -o export $raid | awk -F= '/TYPE/ {print $2}')
    local sync_action=$(cat /sys/block/$raidname/md/sync_action)
    if [ ! $sync_action = "idle" ]; then
        return
    fi
    ter_curl --unix-socket $STORAGE_MANAGER_SOCK http://storage.sock/storage/VgMonitor?raid=${raid}\&event=finish
    logger -t "MDADM-MONITOR" "[RebuildFinished]: raid ${raid} device rebuild finish"
    if [ $status -eq 0 ]; then
        close_buzzer
    fi
    mdadm --grow $raid --size=max >/dev/null 2>&1

    # Align to 512K chunk boundary for RAID5 migration compatibility
    local comp_size=$(cat /sys/block/$raidname/md/component_size 2>/dev/null)
    if [ -n "$comp_size" ] && [ "$comp_size" -gt 0 ]; then
        local aligned_size=$(( (comp_size / 512) * 512 ))
        if [ "$aligned_size" -ne "$comp_size" ]; then
            mdadm --grow $raid --size=$aligned_size >/dev/null 2>&1
            logger -t "MDADM-MONITOR" "[RebuildFinished]: aligned $raid size from $comp_size to $aligned_size (512K boundary)"
        fi
    fi

    if [ "$fs" = "LVM2_member" ]; then
        pvresize -y $raid
        mdadm -Ds >/etc/mdadm.conf
    elif [ "$fs" = "btrfs" ]; then
        local MNTPATH=/mnt/md${sort}
        df-json | grep "$MNTPATH$" >/dev/null
        if [ $? -eq 0 ]; then
            btrfs filesystem resize max $MNTPATH >/dev/null 2>&1
        fi
    elif [ "$fs" = "ext4" ]; then
        resize2fs -f $raid >/dev/null 2>&1
    fi
}

buzzer_raid() {
    local raid=$1
    local raidname=$(basename $raid)
    # 用户已主动关闭蜂鸣器，跳过启动但保留桌面通知
    if [ -f /var/run/buzzer_dismissed/.dismissed ]; then
        # 检查 dismiss 是否已过期（24小时）
        dismissed_time=$(cat /var/run/buzzer_dismissed/.dismissed)
        dismissed_epoch=$(date -d "$dismissed_time" +%s 2>/dev/null)
        now_epoch=$(date +%s)
        if [ -n "$dismissed_epoch" ] && [ $((now_epoch - dismissed_epoch)) -gt 86400 ]; then
            rm -f /var/run/buzzer_dismissed/.dismissed
            logger -t "MDADM-MONITOR" "[buzzer_raid]: dismiss expired for $raid, re-enabling buzzer"
        fi
    fi
    touch /etc/base/.buzzer_$raidname
    # 蜂鸣器已在响，不重复触发，只发桌面通知
    if [ -f $buzzerpid ]; then
        ter_raid_warning $raid
        return
    fi
    if [ -e $buzzer_config ]; then
        status=$(awk -F '=' '/''/{a=1}a==1&&$1~/'raid_drive_miss'/{print $2;exit}' $buzzer_config)
        if [ "$status" != '' ] && [ "$status" -eq '1' ]; then
            systemctl start tnas-warnning.service
        fi
    else
        systemctl start tnas-warnning.service
    fi
    ter_raid_warning $raid
}

close_buzzer_raid() {
    local raid=$1
    local raidname=$(basename $raid)
    local buzzerfile=/etc/base/.buzzer_$raidname
    if [ -e $buzzerfile ]; then
        local degraded=$(cat /sys/block/$raidname/md/degraded 2>/dev/null)
        if [ -z "$degraded" ] || [ "$degraded" -eq 0 ]; then
            close_buzzer
        fi
        rm -f $buzzerfile
    fi
    # RAID 恢复正常，清除 dismiss 标记，允许后续降级时重新告警
    rm -f /var/run/buzzer_dismissed/.dismissed
}

close_buzzer() {
    if [ -f $buzzerpid ]; then
        local pid=$(cat $buzzerpid)
        [ ! -z "$pid" ] && kill $pid
        # kill 后立即复位蜂鸣器，防止信号卡在高点持续响。buzzer 不接受参数，off 仅为语义标识
        /usr/bin/buzzer off
        rm -f $buzzerpid
    fi
}

send_to_check() {
    #check storagepool mdInfo from md
    ter_curl -v -X POST --unix-socket $STORAGE_MANAGER_SOCK http://storage.sock/storage/CheckMdInfo/$1
}

case $1 in
DeviceDisappeared)
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device is disappear"
    ;;
RebuildStarted)
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device is rebuild"
    # start to sync
    close_buzzer_raid $2
    raid=$2
    ter_curl --unix-socket $STORAGE_MANAGER_SOCK http://storage.sock/storage/VgMonitor?raid=${raid}\&event=start
    raidname=$(basename $raid)
    send_to_check $raidname

    #  raidname=$(basename $2)
    #  raidinfo=$(ter_mdadm_tool -name $raidname)
    #  finish_time=$(echo $raidinfo | jq -r .finish_time)
    #  ter_msg_add -c storage -l info -s notification -k raid_sync_start -o ${raidname:2} -o $finish_time
    ;;
Rebuild??)
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device is $1"
    ;;
RebuildFinished)
    # sync finish（包括 recovery 和 reshape 完成）
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device is $1"
    raid=$2
    sync_finish $raid
    raidname=$(basename $raid)
    send_to_check $raidname
    # reshape 或 recovery 完成后，检查阵列是否仍降阶，若是则尝试激活热备盘
    degraded=$(cat /sys/block/$raidname/md/degraded 2>/dev/null)
    if [ "$degraded" -gt 0 ] 2>/dev/null; then
        logger -t "MDADM-MONITOR" "[RebuildFinished]: raid $raid still degraded ($degraded), trying hot spare"
        hotspare $raid
    fi
    ;;
Fail | FailSpare)
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device spare failed"
    raid=$2
    raidname=$(basename $raid)
    send_to_check $raidname
    if [ -b "$2" ]; then
        sign=$(mdadm -D ${raid} | grep ${TOS_USER_SIGN})
        if [ -z "$sign" ]; then
            return 0
        fi
        buzzer_raid $raid
        # reshape 期间不触发热备：此时 recovery 无法启动，ter_hotspare 会消费配置但磁盘无法加入
        # reshape 完成后由 RebuildFinished 事件统一触发热备激活
        sync_action=$(cat /sys/block/$raidname/md/sync_action 2>/dev/null)
        if [ "$sync_action" != "reshape" ]; then
            hotspare $raid
        else
            log_debug "[Fail]: raid $raidname is reshaping, skip hot spare"
        fi
    fi
    ;;
SpareActive)
    # active a disk
    close_buzzer_raid $2
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device spare active"
    raidname=$(basename $2)
    send_to_check $raidname
    ;;
NewArray)
    # create a new raid
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device create new array"
    ;;
DegradedArray)
    raid=$2
    raidname=$(basename $raid)
    flag_file="$CACHE_DEGRADED_FLAG_DIR/$raidname"
    if [ -f "$flag_file" ]; then
        logger -t "MDADM-MONITOR" "[$1]: raid $raid is degraded cache raid, wait 10 seconds for business decision"
        sleep 10
        if [ ! -b "$raid" ]; then
            logger -t "MDADM-MONITOR" "[$1]: raid $raid has been stopped, no alarm"
            rm -f "$flag_file"
            exit 0
        fi
        rm -f "$flag_file"
        logger -t "MDADM-MONITOR" "[$1]: raid $raid still exists, proceed with alarm"
    fi
    degraded=$(cat /sys/block/$raidname/md/degraded 2>/dev/null)
    if [ "$degraded" -gt 0 ] 2>/dev/null; then
        logger -t "MDADM-MONITOR" "[$1]: raid $raid device degraded"
        send_to_check $raidname
        buzzer_raid $raid
        # reshape 期间不触发热备：recovery 无法启动，ter_hotspare 会消费配置但磁盘无法加入
        # reshape 完成后由 RebuildFinished 事件统一触发热备激活
        sync_action=$(cat /sys/block/$raidname/md/sync_action 2>/dev/null)
        if [ "$sync_action" != "reshape" ]; then
            hotspare $raid
        else
            log_debug "[DegradedArray]: raid $raidname is reshaping, skip hot spare"
        fi
    fi
    ;;
MoveSpare)
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device move spare"
    ;;
SparesMissing)
    logger -t "MDADM-MONITOR" "[$1]: raid $2 device spare missing"
    hotspare $2
    ;;
TestMessage) ;;

esac
