package org.kne.cloud.network.monitor;

import java.util.function.Consumer;

/**
 * 链路状态监控类，负责维护链路的在线状态和在线率。
 * 设计理念：
 * 1. 状态变化时通过回调通知监听者。
 * 2. 在线率采用指数加权移动平均 (EWMA) 算法，平滑且对历史数据有衰减记忆。
 * 3. 自身不启动任何后台线程，状态的更新由外部（例如收到心跳包时）主动触发。
 * 4. 不包含链路名称，名称由外部管理（如 Map<String, LinkStatus>），实现关注点分离。
 */
public class LinkStatus {
    // 状态常量
    public static final int DOWN = 0;
    public static final int UNSTABLE = 1;
    public static final int UP = 2;

    private volatile int state;
    private volatile double reliability; // 在线率，范围 [0.0, 1.0]

    private Consumer<LinkStatus> changeListener;

    // 用于EWMA计算的衰减因子
    private static final double EWMA_ALPHA = 0.9999;

    public LinkStatus() {
        this.state = DOWN;
        this.reliability = 0.0;
    }

    // 状态 getter/setter
    public int getState() {
        return state;
    }

    /**
     * 更新链路状态，并在状态真正改变时通知监听器。
     * @param newState 新状态 (DOWN, UNSTABLE, UP)
     */
    public void setState(int newState) {
        if (this.state == newState) {
            return;
        }
        this.state = newState;
        if (changeListener != null) {
            changeListener.accept(this);
        }
    }

    // 在线率 getter
    public double getReliability() {
        return reliability;
    }

    /**
     * 核心更新方法：基于当前的在线状态，更新在线率。
     * 此方法应由心跳检测等逻辑周期性调用（例如每秒调用一次）。
     * 使用 EWMA 算法: new_ewma = alpha * old_ewma + (1 - alpha) * current_value
     */
    public void updateReliability() {
        double currentOnline = (state == UP) ? 1.0 : 0.0;
        this.reliability = EWMA_ALPHA * this.reliability + (1 - EWMA_ALPHA) * currentOnline;
    }

    /**
     * 注册状态变更监听器
     * @param listener 监听器函数
     */
    public void setChangeListener(Consumer<LinkStatus> listener) {
        this.changeListener = listener;
    }

    // 静态工具方法
    public static String stateToString(int state) {
        switch (state) {
            case DOWN:
                return "○down";
            case UNSTABLE:
                return "●unstable";
            case UP:
                return "●up";
            default:
                return "unknown";
        }
    }

    @Override
    public String toString() {
        return String.format("[%s]%.2f%%",
                stateToString(state), reliability * 100);
    }
}