#!/bin/bash

function usage() {
    echo "Use: $0 interface metric [--force]"
    echo "  interface metric:"
    echo "    1~7   normal priority level (route metric = level*100), persisted to /etc/ed-qml.conf metric= line (dedup)"
    echo "    8~14  degraded priority level (offline), persisted to /var/log/ed-qmi/degraded, NEVER written to config"
    echo "    >14   absolute route metric, runtime only (not persisted)"
    echo "  --force: re-apply runtime metric only, skip all persistence & NM profile (ed-net-monitor periodic re-suppression)"
    exit 0
}

function echo_error(){
    local t_msg=$*
    local t_time=$(date +%Y/%m/%d-%H:%M:%S)
    echo -e "[${t_time}]\t | [ERROR] | ${t_msg}"
}

function echo_info(){
    local t_msg=$*
    local t_time=$(date +%Y/%m/%d-%H:%M:%S)
    echo -e "[${t_time}]\t | [info] | ${t_msg}"
}

DEBUG=${DEBUG:-0}
debug() { [ "$DEBUG" = "1" ] && echo "[DEBUG $(date +%H:%M:%S)] $*" >&2; }

DEGRADED_FILE=/var/log/ed-qmi/degraded

degraded_write() { # $1=iface $2=degraded_level(8~14)
    mkdir -p /var/log/ed-qmi
    grep -v "^$1:" "$DEGRADED_FILE" 2>/dev/null > "$DEGRADED_FILE.tmp" || true
    echo "$1:$2" >> "$DEGRADED_FILE.tmp"
    mv "$DEGRADED_FILE.tmp" "$DEGRADED_FILE"
}

degraded_remove() { # $1=iface
    [ -f "$DEGRADED_FILE" ] || return 0
    grep -v "^$1:" "$DEGRADED_FILE" > "$DEGRADED_FILE.tmp" 2>/dev/null || true
    mv "$DEGRADED_FILE.tmp" "$DEGRADED_FILE"
}

config_write_metric() { # $1=iface $2=level(1~7)
    local conf=/etc/ed-qml.conf
    local tmp perms
    tmp=$(mktemp)
    perms=$(stat -c %a "$conf" 2>/dev/null || echo 644)
    awk -v iface="$1" -v level="$2" '
        /^[ \t]*metric[ \t]*=/ {
            found=1
            prefix=$0
            sub(/metric[ \t]*=.*$/, "metric=", prefix)  # 保留行首空白 + "metric="
            val=$0
            sub(/^[ \t]*metric[ \t]*=[ \t]*/, "", val)
            n=split(val, a, ",")
            out=""; c=0; done=0
            for (i=1;i<=n;i++) {
                e=a[i]
                gsub(/^[ \t]+|[ \t]+$/, "", e)
                if (e=="") continue
                split(e, b, ":")
                if (b[1]==iface) {
                    if (done) continue                 # 去重：同接口只保留一条
                    e=iface":"level                    # 已存在 → 原位修改等级
                    done=1
                }
                if (c>0) out=out","
                out=out e
                c++
            }
            if (!done) {                               # 不存在 → 追加写入
                if (c>0) out=out","
                out=out iface":"level
            }
            print prefix out
            next
        }
        { print }
        END {
            if (!found) print "metric=" iface ":" level   # 无 metric= 行 → 文件末尾新建
        }
    ' "$conf" > "$tmp" && chmod "$perms" "$tmp" && mv "$tmp" "$conf"
    rm -f "$tmp"
}

if [ "$(id -u)" -ne 0 ]; then
    echo "Script must be run as root. Try 'sudo $0'"
    exit 1
fi

FORCE=0
if [ "$#" -eq 3 ] && [ "$3" = "--force" ];then
    INTERFACE=$1
    PRIORITY=$2
    FORCE=1
elif [ $# -eq 2 ];then
    INTERFACE=$1
    PRIORITY=$2
    FORCE=0
else
    usage
    exit 1
fi

if [ "$PRIORITY" -ge 1 ] 2>/dev/null && [ "$PRIORITY" -le 7 ] 2>/dev/null; then
    LEVEL=$PRIORITY
    NEW_METRIC=$((PRIORITY * 100))
elif [ "$PRIORITY" -ge 8 ] 2>/dev/null && [ "$PRIORITY" -le 14 ] 2>/dev/null; then
    LEVEL=$PRIORITY
    case $PRIORITY in
        8)  NEW_METRIC=800 ;;
        9)  NEW_METRIC=801 ;;
        10) NEW_METRIC=802 ;;
        11) NEW_METRIC=803 ;;
        12) NEW_METRIC=804 ;;
        13) NEW_METRIC=810 ;;
        14) NEW_METRIC=820 ;;
    esac
else
    LEVEL=""
    NEW_METRIC=$PRIORITY
fi

if [ -z "$INTERFACE" ]; then
    debug "ABORT: empty INTERFACE (likely connectivity-change)"
    echo "ABORT: interface name required" >&2
    exit 2
fi

debug "=== START pid=$$ iface=$INTERFACE input=$PRIORITY level='$LEVEL' metric=$NEW_METRIC force=$FORCE ==="
debug "CONFIG: $(grep -E '^[[:space:]]*metric=' /etc/ed-qml.conf 2>/dev/null | head -1)"
debug "DEGRADED: $(cat $DEGRADED_FILE 2>/dev/null | tr '\n' ' ')"
debug "LINK_STATE: $(cat /sys/class/net/${INTERFACE}/operstate 2>/dev/null || echo unknown)"

if [ "$FORCE" -eq 0 ]; then
    if [ -n "$LEVEL" ]; then
        if [ "$LEVEL" -ge 1 ] 2>/dev/null && [ "$LEVEL" -le 7 ] 2>/dev/null; then
            degraded_remove "$INTERFACE"
            config_write_metric "$INTERFACE" "$LEVEL"
        else
            degraded_write "$INTERFACE" "$LEVEL"
        fi
    else
        debug "WRITE_SKIP: ${INTERFACE} absolute metric ${NEW_METRIC} not persisted (runtime-only)"
    fi
else
    debug "FORCE: skip persistence, runtime re-apply only"
fi

if [ "$FORCE" -eq 0 ] && { [ -z "$LEVEL" ] || [ "$LEVEL" -le 7 ] 2>/dev/null; }; then
    NM_CONN=$(nmcli -t -f GENERAL.CONNECTION device show "$INTERFACE" 2>/dev/null \
        | grep "GENERAL.CONNECTION:" | cut -d: -f2)
    debug "NM_CONN: '$NM_CONN'"
    if [ -n "$NM_CONN" ]; then
        nmcli connection modify "$NM_CONN" ipv4.route-metric "$NEW_METRIC" 2>/dev/null || debug "NMCLI: modify failed"
    else
        debug "NMCLI: no connection found, profile not updated"
    fi
else
    debug "NM_SKIP: degraded/force, NM profile untouched"
fi

debug "--- PHASE 1: dedup (preserves lowest-metric route) ---"
seen_file=$(mktemp)
ip route show | grep "dev $INTERFACE" | while read -r route; do
    route=$(echo "$route" | sed 's/ linkdown//')
    prefix=$(echo "$route" | awk '{print $1}')
    if grep -qx "$prefix" "$seen_file" 2>/dev/null; then
        echo "removing duplicate: ${route}"
        ip route del $route 2>/dev/null || true
    else
        echo "$prefix" >> "$seen_file"
    fi
done
rm -f "$seen_file"

ip route show | grep "dev $INTERFACE" | while read -r route; do
    route=$(echo "$route" | sed 's/ linkdown//')
    echo "$route" | grep -q "metric ${NEW_METRIC}" && continue

    echo "modify: ${route}"
    if ! echo "$route" | grep -q "metric"; then
        new_route=$(echo "$route" | sed -E "s/$/ metric ${NEW_METRIC}/")
    else
        new_route=$(echo "$route" | sed -E "s/metric [0-9]+/metric ${NEW_METRIC}/")
    fi

    ip route change $new_route 2>/dev/null
    if [ $? -ne 0 ]; then
        ip route del $route 2>/dev/null || true
        ip route add $new_route 2>/dev/null || true
    fi
done

ip route show | grep "dev $INTERFACE" | while read -r route; do
    route=$(echo "$route" | sed 's/ linkdown//')
    echo "$route" | grep -q "metric" || continue
    cur_metric=$(echo "$route" | sed -E 's/.* metric ([0-9]+).*/\1/')
    if [ "$cur_metric" != "$NEW_METRIC" ]; then
        echo "cleanup: ${route}"
        ip route del $route 2>/dev/null || true
    fi
done
