#!/bin/bash
# AethEx GPIO 离线更新脚本（随更新包携带，在目标板上执行）
#
# 两阶段更新机制（含内核时）：
#   Phase 1: 安装内核 → 持久化更新包 → 注册续装服务 → 重启
#   Phase 2: 重启后自动触发 → 跳过内核 → 安装应用 → 清理
#
# 不含内核时：一次性完成全部安装（行为与旧版一致）
#
# 用法:
#   tar xzf aethex_gpio_update_*.tar.gz
#   bash pkg/update.sh

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
BACKUP_DIR="/var/lib/aethex_gpio/backup"
STATE_FILE="/var/lib/aethex_gpio/update_state"
CURRENT_VERSION_FILE="/etc/aethex_gpio_version"
# 两阶段更新持久化目录
PENDING_DIR="/var/lib/aethex_gpio/pending_pkg"
KERNEL_DONE_MARKER="/var/lib/aethex_gpio/.kernel_updated"
RESUME_SERVICE="aethex-resume-update.service"

RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
log_info()  { echo -e "${GREEN}[INFO]${NC}  $*"; }
log_warn()  { echo -e "${YELLOW}[WARN]${NC}  $*"; }
log_error() { echo -e "${RED}[ERROR]${NC} $*"; }

# ---------------------------------------------------------------------------
# 备份当前版本
# ---------------------------------------------------------------------------
do_backup() {
    log_info "备份当前版本..."
    rm -rf "${BACKUP_DIR}"
    mkdir -p "${BACKUP_DIR}"

    # 备份二进制文件
    [[ -f /usr/bin/aethex_gpio ]] && cp /usr/bin/aethex_gpio "${BACKUP_DIR}/"
    [[ -f /usr/bin/aethex_gpio_cli ]] && cp /usr/bin/aethex_gpio_cli "${BACKUP_DIR}/"

    # 备份脚本
    mkdir -p "${BACKUP_DIR}/lib"
    [[ -f /usr/lib/aethex_gpio/wifi_ap.sh ]] && cp /usr/lib/aethex_gpio/wifi_ap.sh "${BACKUP_DIR}/lib/"
    [[ -f /usr/lib/aethex_gpio/auto_update.sh ]] && cp /usr/lib/aethex_gpio/auto_update.sh "${BACKUP_DIR}/lib/"

    # 备份 systemd 服务文件
    [[ -f /etc/systemd/system/aethex_gpio.service ]] && cp /etc/systemd/system/aethex_gpio.service "${BACKUP_DIR}/"
    [[ -f /etc/systemd/system/aethex_ota.service ]] && cp /etc/systemd/system/aethex_ota.service "${BACKUP_DIR}/"
    [[ -f /etc/systemd/system/aethex_ota.timer ]] && cp /etc/systemd/system/aethex_ota.timer "${BACKUP_DIR}/"

    # 备份版本文件
    [[ -f "${CURRENT_VERSION_FILE}" ]] && cp "${CURRENT_VERSION_FILE}" "${BACKUP_DIR}/"

    log_info "备份完成: ${BACKUP_DIR}"
}

# ---------------------------------------------------------------------------
# 回滚到备份版本
# ---------------------------------------------------------------------------
do_rollback() {
    log_error "安装失败，正在回滚..."

    if [[ ! -d "${BACKUP_DIR}" ]]; then
        log_error "无备份文件，无法回滚"
        return 1
    fi

    # 恢复二进制文件
    [[ -f "${BACKUP_DIR}/aethex_gpio" ]] && cp "${BACKUP_DIR}/aethex_gpio" /usr/bin/
    [[ -f "${BACKUP_DIR}/aethex_gpio_cli" ]] && cp "${BACKUP_DIR}/aethex_gpio_cli" /usr/bin/

    # 恢复脚本
    [[ -f "${BACKUP_DIR}/lib/wifi_ap.sh" ]] && cp "${BACKUP_DIR}/lib/wifi_ap.sh" /usr/lib/aethex_gpio/
    [[ -f "${BACKUP_DIR}/lib/auto_update.sh" ]] && cp "${BACKUP_DIR}/lib/auto_update.sh" /usr/lib/aethex_gpio/

    # 恢复 systemd 服务文件
    [[ -f "${BACKUP_DIR}/aethex_gpio.service" ]] && cp "${BACKUP_DIR}/aethex_gpio.service" /etc/systemd/system/
    [[ -f "${BACKUP_DIR}/aethex_ota.service" ]] && cp "${BACKUP_DIR}/aethex_ota.service" /etc/systemd/system/
    [[ -f "${BACKUP_DIR}/aethex_ota.timer" ]] && cp "${BACKUP_DIR}/aethex_ota.timer" /etc/systemd/system/

    # 恢复版本文件
    [[ -f "${BACKUP_DIR}/aethex_gpio_version" ]] && cp "${BACKUP_DIR}/aethex_gpio_version" "${CURRENT_VERSION_FILE}"

    # 恢复内核文件（如果有备份）
    if [[ -d "${BACKUP_DIR}/boot" ]]; then
        ensure_boot_mounted
        [[ -f "${BACKUP_DIR}/boot/Image.gz" ]] && cp "${BACKUP_DIR}/boot/Image.gz" /boot/
        for dtb in "${BACKUP_DIR}/boot/"*.dtb; do
            [[ -f "${dtb}" ]] && cp "${dtb}" /boot/
        done
        log_info "内核文件已回滚"
    fi

    systemctl daemon-reload

    log_info "回滚完成"
}

# ---------------------------------------------------------------------------
# 确保 /boot 分区已挂载
# ---------------------------------------------------------------------------
ensure_boot_mounted() {
    if mountpoint -q /boot; then
        return 0
    fi

    mount LABEL=bootfs /boot 2>/dev/null && return 0

    for dev in /dev/mmcblk1p6 /dev/mmcblk0p4; do
        [[ -b "${dev}" ]] && mount "${dev}" /boot 2>/dev/null && return 0
    done

    log_error "无法挂载 /boot 分区"
    return 1
}

# ---------------------------------------------------------------------------
# 确保 fstab 中有 /boot 条目（永久挂载）
# ---------------------------------------------------------------------------
ensure_boot_fstab() {
    if grep -q "^[^#].*/boot" /etc/fstab 2>/dev/null; then
        return 0
    fi

    log_info "添加 /boot 挂载到 fstab..."
    echo 'LABEL=bootfs  /boot  ext4  defaults,sync  0  1' >> /etc/fstab
}

# ---------------------------------------------------------------------------
# Phase 1: 安装内核组件（仅内核，不启动应用）
# ---------------------------------------------------------------------------
install_kernel() {
    local kernel_dir="${SCRIPT_DIR}/kernel"

    log_info "=== Phase 1: 安装内核 ==="

    ensure_boot_mounted || return 1
    ensure_boot_fstab

    # 备份当前内核文件
    mkdir -p "${BACKUP_DIR}/boot"
    [[ -f /boot/Image.gz ]] && cp /boot/Image.gz "${BACKUP_DIR}/boot/"
    for dtb in /boot/*.dtb; do
        [[ -f "${dtb}" ]] && cp "${dtb}" "${BACKUP_DIR}/boot/"
    done

    # 安装内核镜像
    if [[ -f "${kernel_dir}/Image.gz" ]]; then
        cp "${kernel_dir}/Image.gz" /boot/Image.gz.new
        sync
        mv /boot/Image.gz.new /boot/Image.gz
        log_info "内核镜像已更新: /boot/Image.gz"
    elif [[ -f "${kernel_dir}/Image" ]]; then
        gzip -c "${kernel_dir}/Image" > /boot/Image.gz.new
        sync
        mv /boot/Image.gz.new /boot/Image.gz
        log_info "内核镜像已更新: /boot/Image.gz (从 Image 压缩)"
    fi

    # 安装设备树
    local dtb_count=0
    for dtb_file in "${kernel_dir}"/*.dtb; do
        [[ -f "${dtb_file}" ]] || continue
        local dtb_name
        dtb_name=$(basename "${dtb_file}")
        cp "${dtb_file}" "/boot/${dtb_name}.new"
        sync
        mv "/boot/${dtb_name}.new" "/boot/${dtb_name}"
        dtb_count=$((dtb_count + 1))
    done
    [[ ${dtb_count} -gt 0 ]] && log_info "设备树已更新: ${dtb_count} 个 DTB 文件"

    # 安装内核模块
    if [[ -f "${kernel_dir}/modules.tar" ]]; then
        cd /lib/modules
        tar xf "${kernel_dir}/modules.tar"
        depmod -a
        log_info "内核模块已更新"
        cd "${SCRIPT_DIR}"
    fi

    log_info "内核安装完成"
}

# ---------------------------------------------------------------------------
# 注册重启后续装服务（oneshot systemd service）
# ---------------------------------------------------------------------------
register_resume_service() {
    log_info "注册重启后续装服务..."

    cat > "/etc/systemd/system/${RESUME_SERVICE}" <<EOF
[Unit]
Description=AethEx GPIO 更新续装 (Phase 2)
After=network.target
ConditionPathExists=${KERNEL_DONE_MARKER}

[Service]
Type=oneshot
ExecStart=/bin/bash ${PENDING_DIR}/update.sh
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target
EOF

    systemctl daemon-reload
    systemctl enable "${RESUME_SERVICE}"
    log_info "续装服务已注册: ${RESUME_SERVICE}"
}

# ---------------------------------------------------------------------------
# 清理两阶段更新残留
# ---------------------------------------------------------------------------
cleanup_two_phase() {
    rm -f "${KERNEL_DONE_MARKER}"
    systemctl disable "${RESUME_SERVICE}" 2>/dev/null || true
    rm -f "/etc/systemd/system/${RESUME_SERVICE}"
    systemctl daemon-reload 2>/dev/null || true
    # 清理持久化包（保留一段时间以便排查问题）
    # rm -rf "${PENDING_DIR}"  # 暂不删除，成功后由 cleanup_backup 处理
    log_info "两阶段更新清理完成"
}

# ---------------------------------------------------------------------------
# 清理备份（安装成功后调用）
# ---------------------------------------------------------------------------
cleanup_backup() {
    if [[ -d "${BACKUP_DIR}" ]]; then
        echo "backup_time=$(date '+%Y-%m-%d %H:%M:%S')" > "${BACKUP_DIR}/.backup_info"
        find "${BACKUP_DIR}" -type f ! -name ".backup_info" -delete 2>/dev/null || true
    fi
    # 清理持久化包
    rm -rf "${PENDING_DIR}"
}

# ---------------------------------------------------------------------------
# 设置更新状态
# ---------------------------------------------------------------------------
set_state() {
    local state="$1"
    mkdir -p "$(dirname "${STATE_FILE}")"
    echo "state=${state}" > "${STATE_FILE}"
    echo "time=$(date '+%Y-%m-%d %H:%M:%S')" >> "${STATE_FILE}"
    [[ -f "${SCRIPT_DIR}/VERSION" ]] && echo "version=$(cat "${SCRIPT_DIR}/VERSION")" >> "${STATE_FILE}"
}

# ---------------------------------------------------------------------------
# 判断是否需要两阶段更新
# ---------------------------------------------------------------------------
needs_two_phase() {
    # 有内核目录 且 内核尚未安装完成
    [[ -d "${SCRIPT_DIR}/kernel" ]] && [[ ! -f "${KERNEL_DONE_MARKER}" ]]
}

is_phase2() {
    # 内核已标记完成，当前是续装阶段
    [[ -f "${KERNEL_DONE_MARKER}" ]]
}

# ---------------------------------------------------------------------------
# Phase 1 主流程：仅安装内核，持久化包，重启
# ---------------------------------------------------------------------------
run_phase1() {
    log_info "检测到内核更新，执行两阶段更新..."
    log_info "Phase 1: 安装内核 → 重启 → Phase 2: 安装应用"
    echo

    set_state "phase1_kernel"

    # 备份
    do_backup

    trap 'do_rollback; exit 1' ERR

    # 安装内核
    install_kernel

    trap - ERR

    # 持久化更新包到固定位置（跨重启保留）
    log_info "持久化更新包..."
    rm -rf "${PENDING_DIR}"
    cp -a "${SCRIPT_DIR}" "${PENDING_DIR}"

    # 写入内核完成标记
    mkdir -p "$(dirname "${KERNEL_DONE_MARKER}")"
    echo "kernel_updated=$(date '+%Y-%m-%d %H:%M:%S')" > "${KERNEL_DONE_MARKER}"
    echo "pkg_dir=${PENDING_DIR}" >> "${KERNEL_DONE_MARKER}"

    # 注册重启后自动续装服务
    register_resume_service

    set_state "phase1_done_rebooting"

    echo
    log_warn "================================================"
    log_warn "  内核已更新，设备将在 10 秒后重启"
    log_warn "  重启后将自动执行 Phase 2（应用安装）"
    log_warn "================================================"
    echo

    sync
    sleep 10
    reboot
}

# ---------------------------------------------------------------------------
# Phase 2 / 单阶段主流程：安装应用
# ---------------------------------------------------------------------------
run_app_install() {
    if is_phase2; then
        log_info "=== Phase 2: 重启完成，继续安装应用 ==="
        echo
    fi

    set_state "updating_app"

    # 停止服务
    log_info "停止服务..."
    systemctl stop aethex_wifi_monitor 2>/dev/null || true
    systemctl disable aethex_wifi_monitor 2>/dev/null || true
    rm -f /etc/systemd/system/aethex_wifi_monitor.service

    systemctl stop aethex_gpio 2>/dev/null || true
    sleep 1

    # 如果不是 Phase 2（即无内核更新的单阶段），这里才做备份
    if ! is_phase2; then
        do_backup
    fi

    # 安装文件（使用 trap 确保失败时回滚）
    trap 'do_rollback; exit 1' ERR

    log_info "安装文件..."
    install -d /usr/lib/aethex_gpio

    # 原子安装：先写到临时文件，再移动
    install -m 755 "${SCRIPT_DIR}/build/aethex_gpio"          /usr/bin/aethex_gpio.new
    install -m 755 "${SCRIPT_DIR}/build/aethex_gpio_cli"      /usr/bin/aethex_gpio_cli.new
    mv /usr/bin/aethex_gpio.new /usr/bin/aethex_gpio
    mv /usr/bin/aethex_gpio_cli.new /usr/bin/aethex_gpio_cli

    install -m 755 "${SCRIPT_DIR}/scripts/wifi_ap.sh"         /usr/lib/aethex_gpio/wifi_ap.sh
    rm -f /usr/lib/aethex_gpio/wifi_monitor.sh

    # 安装 MAC 地址设置脚本
    if [[ -f "${SCRIPT_DIR}/set_unique_mac.sh" ]]; then
        install -m 755 "${SCRIPT_DIR}/set_unique_mac.sh" /usr/lib/aethex_gpio/set_unique_mac.sh
        log_info "MAC 设置脚本已安装"
    fi

    # 安装设备标识设置脚本
    if [[ -f "${SCRIPT_DIR}/set_device_identity.sh" ]]; then
        install -m 755 "${SCRIPT_DIR}/set_device_identity.sh" /usr/lib/aethex_gpio/set_device_identity.sh
        log_info "设备标识设置脚本已安装"
    fi

    # 安装 OTA 客户端
    if [[ -f "${SCRIPT_DIR}/auto_update.sh" ]]; then
        install -m 755 "${SCRIPT_DIR}/auto_update.sh" /usr/lib/aethex_gpio/auto_update.sh
        log_info "OTA 客户端已安装"
        ln -sf /usr/lib/aethex_gpio/auto_update.sh /usr/bin/aethex-update
    fi

    # 安装 OTA 签名验证公钥
    if [[ -f "${SCRIPT_DIR}/ota_verify.pub" ]]; then
        install -d /etc/aethex_gpio
        install -m 644 "${SCRIPT_DIR}/ota_verify.pub" /etc/aethex_gpio/ota_verify.pub
        log_info "OTA 验证公钥已安装"
    fi

    [[ -f "${SCRIPT_DIR}/aethex_gpio.service" ]] && \
        install -m 644 "${SCRIPT_DIR}/aethex_gpio.service" \
            /etc/systemd/system/aethex_gpio.service

    [[ -f "${SCRIPT_DIR}/aethex_ota.service" ]] && \
        install -m 644 "${SCRIPT_DIR}/aethex_ota.service" \
            /etc/systemd/system/aethex_ota.service

    [[ -f "${SCRIPT_DIR}/aethex_ota.timer" ]] && \
        install -m 644 "${SCRIPT_DIR}/aethex_ota.timer" \
            /etc/systemd/system/aethex_ota.timer

    [[ -f "${SCRIPT_DIR}/aethex-set-mac.service" ]] && \
        install -m 644 "${SCRIPT_DIR}/aethex-set-mac.service" \
            /etc/systemd/system/aethex-set-mac.service

    [[ -f "${SCRIPT_DIR}/aethex-set-identity.service" ]] && \
        install -m 644 "${SCRIPT_DIR}/aethex-set-identity.service" \
            /etc/systemd/system/aethex-set-identity.service

    # 安装 rtty 服务（含设备标识修正）
    if [[ -f "${SCRIPT_DIR}/rtty.service" ]]; then
        install -m 644 "${SCRIPT_DIR}/rtty.service" /etc/systemd/system/rtty.service
        log_info "rtty 服务已安装（AethEx-{DevSN} 格式）"
    fi

    # 安装 storage manager
    if [[ -d "${SCRIPT_DIR}/storage_manager" ]]; then
        log_info "安装 storage manager..."
        install -m 755 "${SCRIPT_DIR}/storage_manager/mount-to-homepi.sh" \
            /usr/local/bin/mount-to-homepi.sh
        install -m 644 "${SCRIPT_DIR}/storage_manager/90-automount-homepi.rules" \
            /etc/udev/rules.d/90-automount-homepi.rules
        udevadm control --reload-rules 2>/dev/null || true
        udevadm trigger 2>/dev/null || true
        log_info "storage manager 已安装"
    fi

    # 安装网络配置（修复 end1/end2/4G 路由优先级）
    if [[ -d "${SCRIPT_DIR}/network" ]]; then
        log_info "更新网络配置..."
        rm -f /etc/systemd/network/*.network /etc/systemd/network/*.network~
        for nf in "${SCRIPT_DIR}/network/"*.network; do
            [[ -f "${nf}" ]] && install -m 644 "${nf}" /etc/systemd/network/
        done

        # 安装 4G metric 修正脚本
        if [[ -f "${SCRIPT_DIR}/network/fix_4g_metric.sh" ]]; then
            install -m 755 "${SCRIPT_DIR}/network/fix_4g_metric.sh" /usr/lib/aethex_gpio/fix_4g_metric.sh
        fi

        # 安装 udev 规则：4G 接口 up 时自动修正 metric
        if [[ -f "${SCRIPT_DIR}/network/91-fix-4g-metric.rules" ]]; then
            install -m 644 "${SCRIPT_DIR}/network/91-fix-4g-metric.rules" /etc/udev/rules.d/91-fix-4g-metric.rules
            udevadm control --reload-rules 2>/dev/null || true
        fi

        systemctl restart systemd-networkd 2>/dev/null || true

        # 立即修正当前 4G 路由（如果已在线）
        /usr/lib/aethex_gpio/fix_4g_metric.sh 2>/dev/null &

        log_info "网络配置已更新（end1=DHCP metric100, end2=静态192.168.0.101, 4G=metric2048）"
    fi

    # 移除错误陷阱
    trap - ERR

    log_info "重新加载服务..."
    systemctl daemon-reload
    systemctl enable aethex-set-mac.service 2>/dev/null || true
    systemctl enable aethex-set-identity.service 2>/dev/null || true
    systemctl enable aethex_gpio
    systemctl enable aethex_ota.timer 2>/dev/null || true
    # rtty is installed but not auto-enabled (use 'aethex_gpio_cli rtty on' manually)

    # MAC 设置
    if [[ -f /usr/lib/aethex_gpio/set_unique_mac.sh ]]; then
        log_info "设置唯一 MAC 地址..."
        /usr/lib/aethex_gpio/set_unique_mac.sh || true
    fi

    # 设备标识
    if [[ -f /usr/lib/aethex_gpio/set_device_identity.sh ]]; then
        log_info "设置设备标识..."
        /usr/lib/aethex_gpio/set_device_identity.sh || true
    fi

    # 启动服务并验证
    log_info "启动服务..."
    systemctl start aethex_gpio
    sleep 2
    systemctl start aethex_ota.timer 2>/dev/null || true
    sleep 3

    # 验证服务状态
    if ! systemctl is-active --quiet aethex_gpio; then
        log_error "服务启动失败，尝试回滚..."
        do_rollback
        systemctl start aethex_gpio || true
        log_error "更新失败，已回滚到旧版本"
        set_state "failed"
        exit 1
    fi

    # 记录版本
    [[ -f "${SCRIPT_DIR}/VERSION" ]] && \
        echo "$(cat "${SCRIPT_DIR}/VERSION") updated:$(date '+%Y-%m-%d %H:%M')" \
            > "${CURRENT_VERSION_FILE}"

    # 配置 OTA 服务器
    if [[ -f "${SCRIPT_DIR}/OTA_SERVER" ]]; then
        OTA_URL=$(cat "${SCRIPT_DIR}/OTA_SERVER")
        /usr/lib/aethex_gpio/auto_update.sh --set-server "${OTA_URL}" && \
            log_info "OTA 服务器已配置: ${OTA_URL}" || \
            log_warn "OTA 服务器配置失败"
    fi

    # 清理两阶段残留（如果是 Phase 2）
    if is_phase2; then
        cleanup_two_phase
    fi

    # 清理备份
    cleanup_backup

    # 更新状态
    set_state "success"

    echo
    log_info "验证结果:"
    systemctl is-active aethex_gpio && echo "  [OK] aethex_gpio" || echo "  [FAIL] aethex_gpio"

    echo
    aethex_gpio_cli status || true
    log_info "更新完成!"
}

# ---------------------------------------------------------------------------
# 主入口
# ---------------------------------------------------------------------------
main() {
    log_info "AethEx GPIO 更新"
    [[ -f "${SCRIPT_DIR}/VERSION" ]] && log_info "包版本: $(cat "${SCRIPT_DIR}/VERSION")"
    echo

    if needs_two_phase; then
        # 含内核且尚未完成 Phase 1 → 执行内核安装+重启
        run_phase1
    else
        # 无内核（单阶段） 或 Phase 2（内核已装好，续装应用）
        run_app_install
    fi
}

main "$@"
