#!/bin/sh
#
# fix_database_to_sd.sh
# 用途: 修复 database 数据落盘 eMMC 问题，将数据迁移至 SD 卡/TF 卡
# 适用: 所有 WLOSANY 系列板型
# 用法: sh fix_database_to_sd.sh
#
set -e

LOG_FILE="/tmp/fix_database_$(date +%Y%m%d_%H%M%S).log"

# 全局状态变量
SN=""
BOARD=""
PRODUCT=""
FINAL_RESULT=""   # SUCCESS / SKIP / FAIL_MOUNT / FAIL / UNKNOWN

# ==================================================================
# 日志函数
# ==================================================================
log()     { local m="[$(date '+%m-%d %H:%M:%S')] $*"; echo "$m" | tee -a "$LOG_FILE"; }
log_i()   { log "INFO   $*"; }
log_w()   { log "WARN   $*"; }
log_e()   { log "ERROR  $*"; }
log_ok()  { log "OK     $*"; }
log_hdr() { echo "" | tee -a "$LOG_FILE"; log "============================================================"; log "$*"; }

# ==================================================================
# 获取设备 SN
# ==================================================================
get_sn() {
    SN=$(factory get 2>/dev/null | awk -F= '/^SN=/{print $2}')
    if [ -z "$SN" ]; then
        SN="unknown"
    fi
}

# ==================================================================
# 最终总结行
# ==================================================================
print_final_summary() {
    echo "" | tee -a "$LOG_FILE"
    log "============================================================"
    log "最终结果: SN=$SN  BOARD=$BOARD  PRODUCT=$PRODUCT  状态=$FINAL_RESULT"
    log "日志文件: $LOG_FILE"
    log "============================================================"
}

# ==================================================================
# 步骤1: 识别设备类型
#   规则:
#     1. 读取 /tmp/sysinfo/board_name
#     2. WLOSANY_RK3568              → SSD (/mnt/ssd)
#     3. WLOSANY_BAU-B30-003         → SSD (/mnt/ssd)
#     4. WLOSANY_LC100 + PRODUCT含500 → TF卡 (/mnt/sdisk)
#     5. 其他情况                      → 未知版型，退出
# ==================================================================
step1_detect() {
    log_hdr "步骤1: 识别设备类型"

    # 读取板型
    BOARD=$(cat /tmp/sysinfo/board_name 2>/dev/null || echo "")
    if [ -z "$BOARD" ]; then
        log_e "无法读取 board_name (/tmp/sysinfo/board_name)，退出"
        FINAL_RESULT="FAIL"
        print_final_summary
        exit 1
    fi
    log_i "板型: $BOARD"

    case "$BOARD" in
        WLOSANY_RK3568|WLOSANY_BAU-B30-003)
            # RK3568 / BAU-B30-003 板型使用 SSD
            SD_PATH="/mnt/ssd"
            SD_NAME="SSD"
            log_i "存储类型: SSD ($BOARD)"
            ;;

        WLOSANY_LC100)
            # LC100 板型需进一步读取 PRODUCT 判断
            PRODUCT=$(factory get 2>/dev/null | awk -F= '/^PRODUCT=/{print $2}')
            if [ -z "$PRODUCT" ]; then
                log_w "无法读取 PRODUCT (factory get)，标记为未知版型"
                FINAL_RESULT="UNKNOWN"
                print_final_summary
                exit 0
            fi
            log_i "PRODUCT: $PRODUCT"

            case "$PRODUCT" in
                *500*)
                    SD_PATH="/mnt/sdisk"
                    SD_NAME="TF卡(sdisk)"
                    log_i "存储类型: TF卡 (PRODUCT含500)"
                    ;;
                *)
                    # PRODUCT 不含 500 → 未知版型
                    log_w "LC100 板型但 PRODUCT=$PRODUCT 不含 500，标记为未知版型"
                    FINAL_RESULT="UNKNOWN"
                    print_final_summary
                    exit 0
                    ;;
            esac
            ;;

        *)
            # 未知板型
            log_w "未知板型: $BOARD，标记为未知版型"
            FINAL_RESULT="UNKNOWN"
            print_final_summary
            exit 0
            ;;
    esac

    LINK_DB="/opt/lnxall_app/app/database"
    DIR_DB_SD="${SD_PATH}/database"

    log_i "存储类型: $SD_NAME"
    log_i "挂载路径: $SD_PATH"
    log_i "database 链接: $LINK_DB"
    log_i "database 目标: $DIR_DB_SD"
}

# ==================================================================
# 步骤2: 检查 SD 卡挂载（未挂载时先尝试自动挂载）
# ==================================================================
step2_mount() {
    log_hdr "步骤2: 检查 SD 卡挂载"

    if mount | grep -q "$SD_PATH"; then
        log_ok "$SD_NAME 已挂载 ($SD_PATH)"
        return 0
    fi

    # ---- 未挂载，尝试自动挂载 ----
    log_w "$SD_NAME 未挂载 ($SD_PATH)，尝试自动挂载..."

    local DEV=""
    if [ "$SD_PATH" = "/mnt/ssd" ]; then
        for d in nvme0n1 sda; do
            if [ -b "/dev/$d" ]; then
                DEV="/dev/$d"
                break
            fi
        done
    else
        DEV=$(ls /dev/mmcblk?p? 2>/dev/null | head -1)
        if [ -z "$DEV" ]; then
            DEV=$(ls /dev/mmcblk? 2>/dev/null | head -1)
        fi
    fi

    if [ -z "$DEV" ]; then
        log_e "未找到可用的块设备"
        FINAL_RESULT="FAIL_MOUNT"
        print_final_summary
        exit 2
    fi

    log_i "找到块设备: $DEV"

    if [ ! -d "$SD_PATH" ]; then
        if [ -L "$SD_PATH" ]; then
            rm -f "$SD_PATH"
        fi
        mkdir -p "$SD_PATH"
        log_i "已创建挂载点: $SD_PATH"
    elif [ -L "$SD_PATH" ]; then
        rm -f "$SD_PATH"
        mkdir -p "$SD_PATH"
        log_i "已替换软链接为挂载点目录: $SD_PATH"
    fi

    if mount "$DEV" "$SD_PATH" 2>/dev/null; then
        log_ok "自动挂载成功: $DEV → $SD_PATH"
        return 0
    fi

    local FSTYPE=""
    FSTYPE=$(blkid -s TYPE -o value "$DEV" 2>/dev/null)
    if [ -n "$FSTYPE" ]; then
        log_i "文件系统类型: $FSTYPE"
        if mount -t "$FSTYPE" "$DEV" "$SD_PATH" 2>/dev/null; then
            log_ok "自动挂载成功 (类型: $FSTYPE): $DEV → $SD_PATH"
            return 0
        fi
    fi

    rmdir "$SD_PATH" 2>/dev/null || true
    log_e "自动挂载失败"
    log_e ""
    log_e "无法执行修复。请检查:"
    log_e "  1. SD/TF 卡是否正确插入"
    log_e "  2. 硬件卡槽是否松动/损坏"
    log_e "  3. 文件系统是否异常 (dmesg | tail -20)"
    log_e ""
    log_e "修复终止，未修改任何数据。"

    FINAL_RESULT="FAIL_MOUNT"
    print_final_summary
    exit 2
}

# ==================================================================
# 步骤3: 诊断 (纯读，不动任何东西)
# ==================================================================
DIAG_NEED_FIX=0

step3_diagnose() {
    log_hdr "步骤3: 诊断当前状态"

    # ---- 3.1 诊断 database ----
    if [ -L "$LINK_DB" ]; then
        local tgt
        tgt=$(readlink -f "$LINK_DB" 2>/dev/null || readlink "$LINK_DB")
        log_i "database: 软链接 → $tgt"
        if [ "$tgt" = "$DIR_DB_SD" ]; then
            log_ok "  指向正确，无需修复"
        else
            log_w "  指向错误 (应为 $DIR_DB_SD)"
            DIAG_NEED_FIX=1
        fi
    elif [ -d "$LINK_DB" ]; then
        local n
        n=$(find "$LINK_DB" -type f 2>/dev/null | wc -l)
        log_w "database: 普通目录 ($n 个文件，数据在 eMMC)"
        DIAG_NEED_FIX=1
    else
        log_i "database: 不存在"
        DIAG_NEED_FIX=1
    fi

    # ---- 3.2 诊断 /mnt/ssd (仅 TF卡/sdisk 板型) ----
    if [ "$SD_PATH" = "/mnt/sdisk" ]; then
        if [ -L "/mnt/ssd" ]; then
            local tgt
            tgt=$(readlink -f "/mnt/ssd" 2>/dev/null || readlink "/mnt/ssd")
            log_i "/mnt/ssd: 软链接 → $tgt"
            if [ "$tgt" = "/mnt/sdisk" ]; then
                log_ok "  指向正确"
            else
                log_w "  指向错误 (应为 /mnt/sdisk)"
                DIAG_NEED_FIX=1
            fi
        elif [ -d "/mnt/ssd" ]; then
            local n
            n=$(find /mnt/ssd -maxdepth 1 2>/dev/null | wc -l)
            if [ "$n" -gt 1 ]; then
                log_w "/mnt/ssd: 普通目录 ($((n-1)) 项，数据在 eMMC，需手动处理)"
            else
                log_w "/mnt/ssd: 空目录"
                DIAG_NEED_FIX=1
            fi
        else
            log_i "/mnt/ssd: 不存在"
            DIAG_NEED_FIX=1
        fi
    else
        if mount | grep -q "/mnt/ssd"; then
            log_ok "/mnt/ssd: SSD 挂载正常"
        else
            log_w "/mnt/ssd: SSD 未挂载"
        fi
    fi

    # ---- 3.3 结论 ----
    echo "" | tee -a "$LOG_FILE"
    if [ "$DIAG_NEED_FIX" -eq 1 ]; then
        log_w "诊断结论: 需要修复"
    else
        log_ok "诊断结论: 状态正常，无需修复"
        FINAL_RESULT="${FINAL_RESULT:-SKIP}"
    fi
}

# ==================================================================
# 步骤4: 保存服务运行状态 → 停止 → 修复 → 按需重启
# ==================================================================
SVCS_RUNNING=""

save_running_services() {
    SVCS_RUNNING=""
    log_hdr "步骤4: 记录当前运行的服务"
    for s in emsd emud taosd; do
        if systemctl is-active --quiet "$s" 2>/dev/null; then
            SVCS_RUNNING="$SVCS_RUNNING $s"
            log_ok "$s 运行中 → 修复后重启"
        else
            log_i "$s 未运行 → 修复后不启动"
        fi
    done
}

stop_saved_services() {
    for s in $SVCS_RUNNING; do
        systemctl stop "$s" && log_ok "$s 已停止" || log_w "$s 停止失败"
    done
    killall -9 proto_forward 2>/dev/null || true
    killall -9 emu_lc        2>/dev/null || true
    sleep 2
    log_ok "服务全部停止"
}

start_saved_services() {
    log_hdr "步骤6: 重启服务 (仅恢复原本运行的服务)"
    if [ -z "$SVCS_RUNNING" ]; then
        log_i "无需要重启的服务"
        return 0
    fi

    if echo "$SVCS_RUNNING" | grep -q "taosd"; then
        systemctl start taosd && log_ok "taosd 已启动" || log_w "taosd 启动失败"
    fi

    for s in emsd emud; do
        if echo "$SVCS_RUNNING" | grep -q "$s"; then
            systemctl start "$s" && log_ok "$s 已启动" || log_w "$s 启动失败"
        fi
    done

    sleep 2
    log_ok "服务重启完成"
}

step4_fix() {
    if [ "$DIAG_NEED_FIX" -eq 0 ]; then
        return 0
    fi

    save_running_services
    stop_saved_services

    log_hdr "步骤5: 执行修复"

    if [ -L "$LINK_DB" ]; then
        local tgt
        tgt=$(readlink -f "$LINK_DB" 2>/dev/null || readlink "$LINK_DB")
        if [ "$tgt" != "$DIR_DB_SD" ]; then
            log_i "删除错误软链接: $LINK_DB"
            rm -f "$LINK_DB"
        fi
    elif [ -d "$LINK_DB" ]; then
        # 统计需要迁移的普通文件（排除软链接，避免 cp -rL 跟随软链接时循环复制自身）
        local n
        n=$(find "$LINK_DB" -type f 2>/dev/null | wc -l)
        if [ "$n" -gt 0 ]; then
            log_i "迁移 $n 个普通文件到 $DIR_DB_SD ..."
            if [ ! -d "$DIR_DB_SD" ]; then
                mkdir -p "$DIR_DB_SD"
            fi
            # 只复制普通文件，不跟随软链接（避免 db_backup → /mnt/ssd/database 这种循环）
            find "$LINK_DB" -maxdepth 1 -type f -exec cp -a {} "$DIR_DB_SD"/ \; 2>/dev/null || true
            # 重新统计实际成功复制的文件数
            local m
            m=$(find "$DIR_DB_SD" -type f 2>/dev/null | wc -l)
            if [ "$m" -lt "$n" ]; then
                log_w "部分文件未能复制 (源:$n → 目标:$m)，可能是 SQLite journal 临时文件，属正常现象"
            else
                log_ok "迁移完成 (源:$n → 目标:$m)"
            fi
        else
            log_i "目录为空，无需迁移"
        fi
        rm -rf "$LINK_DB"
        log_i "已删除 eMMC 上的旧目录"
    fi

    if [ ! -d "$DIR_DB_SD" ]; then
        mkdir -p "$DIR_DB_SD"
        log_i "已创建: $DIR_DB_SD"
    fi
    if [ ! -e "$LINK_DB" ]; then
        ln -sv "$DIR_DB_SD" "$LINK_DB" 2>&1 | tee -a "$LOG_FILE"
        log_ok "软链接: $LINK_DB → $DIR_DB_SD"
    fi

    if [ "$SD_PATH" = "/mnt/sdisk" ]; then
        if [ -L "/mnt/ssd" ]; then
            local tgt
            tgt=$(readlink -f "/mnt/ssd" 2>/dev/null || readlink "/mnt/ssd")
            if [ "$tgt" != "/mnt/sdisk" ]; then
                rm -f "/mnt/ssd"
            fi
        elif [ -d "/mnt/ssd" ]; then
            local n
            n=$(find /mnt/ssd -maxdepth 1 2>/dev/null | wc -l)
            if [ "$n" -gt 1 ]; then
                log_w "/mnt/ssd 有数据，不自动操作，需手动处理:"
                log_w "  mv /mnt/ssd/* /mnt/sdisk/ && rm -rf /mnt/ssd && ln -s /mnt/sdisk /mnt/ssd"
            else
                rm -rf "/mnt/ssd"
            fi
        fi
        if [ ! -e "/mnt/ssd" ]; then
            ln -sv /mnt/sdisk /mnt/ssd 2>&1 | tee -a "$LOG_FILE"
            log_ok "软链接: /mnt/ssd → /mnt/sdisk"
        fi
    fi

    start_saved_services
    FINAL_RESULT="SUCCESS"
}

# ==================================================================
# 步骤7: 汇总结果
# ==================================================================
step7_summary() {
    log_hdr "步骤7: 修复结果汇总"

    echo "" | tee -a "$LOG_FILE"

    if [ -L "$LINK_DB" ]; then
        log_ok "database → $(readlink -f "$LINK_DB" 2>/dev/null || readlink "$LINK_DB")"
    else
        log_e "database 不是软链接!"
    fi

    if [ -d "$DIR_DB_SD" ]; then
        log_i "${SD_NAME} database 文件数: $(find "$DIR_DB_SD" -type f 2>/dev/null | wc -l)"
    fi

    if [ "$SD_PATH" = "/mnt/sdisk" ]; then
        if [ -L "/mnt/ssd" ]; then
            log_ok "/mnt/ssd → $(readlink /mnt/ssd)"
        elif [ -d "/mnt/ssd" ]; then
            log_w "/mnt/ssd 是普通目录 (数据在 eMMC，需手动处理)"
        else
            log_w "/mnt/ssd 不存在"
        fi
    else
        if mount | grep -q "/mnt/ssd"; then
            log_ok "/mnt/ssd 挂载正常"
        else
            log_w "/mnt/ssd 未挂载"
        fi
    fi

    echo "" | tee -a "$LOG_FILE"
    df -h / "$SD_PATH" 2>/dev/null | tee -a "$LOG_FILE"
}

# ==================================================================
# 主流程
# ==================================================================
main() {
    log "database 存储路径修复脚本 v3.2"
    log "开始时间: $(date '+%Y-%m-%d %H:%M:%S')"

    get_sn
    log_i "设备 SN: $SN"

    step1_detect
    step2_mount
    step3_diagnose

    if [ "$DIAG_NEED_FIX" -eq 1 ]; then
        step4_fix
    else
        log_hdr "无需修复，跳过服务操作"
        FINAL_RESULT="${FINAL_RESULT:-SKIP}"
    fi

    step7_summary
    log "完成时间: $(date '+%Y-%m-%d %H:%M:%S')"

    print_final_summary
}

main "$@"

