package org.kne.cloud.network.congestion;

import java.util.function.Consumer;

public class Vegas2CongestionAlgorithm implements CongestionAlgorithm,DetnetCongestionAlgorithm {
    
    // 可配置的时延膨胀比上下限 - Vegas2.0核心参数
    private double delayUpperBound = 1.20;  // RTT上限为基础RTT的1.2倍
    private double delayLowerBound = 1.15;  // RTT下限为基础RTT的1.05倍
    private double burstLimit=1.20;
    
    private static final long BURST_TIME = 2000000L;
    private static final long BIAS = 1000000L;
	private static long MIN_WINDOW = 16384;
    
    
    private Consumer<Long> windowControlConsumer;

    private long MIN_RTTVAR = 30000000L;
    private volatile long RTTMin = 1000000000L;          // BaseRTT
    private volatile long RTTVar = 1000000000L;
    private volatile long RTTAvg = 1000000000L;
    private volatile long RTTAvg2 = 1000000000L;         // 当前平滑RTT
    private volatile long RTTTotal = 0;
    private volatile long RTTCount = 0;
    private volatile long RTO = 1000000000L;
    

    private volatile long OWDTotal = 0;
    private volatile long OWDCount = 0;
    private volatile long OWDAvg2 = 1000000000L;         // 当前平滑OWD
    private volatile long OWDMin = 1000000000L;          // BaseRTT
    
    private volatile long window = MIN_WINDOW;
    private volatile long window2 = MIN_WINDOW;
    private volatile long maxwindow = 99999999999L;
    public Vegas2CongestionAlgorithm() {
		reset();
	}

	@Override
    public void reset() {
        window = MIN_WINDOW;
        if (windowControlConsumer != null) {
            windowControlConsumer.accept(window);
        }
       
    }

    @Override
    public void setWindowControlConsumer(Consumer<Long> windowControlConsumer) {
        this.windowControlConsumer = windowControlConsumer;
    }

   
    
    private long RTTstartTime = System.nanoTime();
    
   

	@Override
	public void putAck(long packetSize, long RTTns, long OWDup, boolean ecn) {
		if(RTTns<0) {
    		throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
    	}
        // 处理ECN信号 - 将其视为强烈的拥塞信号
        if (ecn) {
            // 当收到ECN时，更激进地减少窗口
        	window2 = Math.max(0, window2 * 3 / 4);
            if (windowControlConsumer != null) {
                windowControlConsumer.accept(window2);
            }
        }
        
        // 更新最小RTT（BaseRTT）
        if (RTTns <= RTTMin) {
            RTTMin = RTTns;
        } else {
            // 缓慢适应：当网络路径真正变化时，BaseRTT应能缓慢更新
            // 这里使用极慢的衰减因子，只有在持续观测到更低RTT时才快速更新
            RTTMin = (RTTMin * 999 + RTTns) / 1000;
        }
        
        // 更新最小OWD（BaseOWD）
        if (OWDup <= OWDMin) {
        	OWDMin = OWDup;
        } else {
            // 缓慢适应：当网络路径真正变化时，BaseRTT应能缓慢更新
            // 这里使用极慢的衰减因子，只有在持续观测到更低RTT时才快速更新
        	OWDMin = (OWDMin * 999 + OWDup) / 1000;
        }
        
        // 更新平滑RTT估计
        
            RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - RTTns)) / 4;
            RTTAvg = (RTTAvg * 7 + RTTns) / 8;
        
        
        RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);
        
        RTTTotal += RTTns;
        RTTCount++;
        
        OWDTotal += OWDup;
        OWDCount++;
        
        long curr = System.nanoTime();
        // 每个RTT周期调整一次窗口（使用当前估计的RTT）
        if (curr - RTTstartTime > Math.max(BIAS, 2*RTTMin)) {
        	long RTTCountx=RTTCount;
            if (RTTCountx > 0) {
                long currentRTT = RTTTotal / RTTCountx;
                //RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4;  // 平滑当前RTT
                RTTAvg2=currentRTT;
                RTTTotal = 0;
                RTTCount = 0;
            }
            
            long OWDCountx=OWDCount;
            if (OWDCountx > 0) {
                long currentOWD = OWDTotal / OWDCountx;
                OWDAvg2=currentOWD;
                OWDTotal = 0;
                OWDCount = 0;
            }
            
            
            // ================== Vegas2.0核心逻辑 ==================
            // 1. 计算时延膨胀比
            double delayRatio = (double) OWDAvg2 / (double) Math.max(BIAS, OWDMin);
            //System.out.println(delayRatio+" "+RTTAvg2/1000000.0+" "+RTTMin/1000000.0);
            // 2. 基于比值的窗口调整（取代原来的基于差值的调整）
            if (delayRatio > delayUpperBound) {
                // 时延过高：减小窗口，减少幅度与超标程度成正比
                window2 -= 4096;
            } else if (delayRatio < delayLowerBound) {
                // 时延过低：增大窗口，增加幅度与低于目标程度成正比
                window2 += 4096;
            } else {
              
            }
            // ===================================================
            
            
            
            
            updateWindowSize();
            RTTstartTime = curr;
            
            
            
            
        }
	}

	@Override
    public  void putAck(long packetSize, long RTTns, boolean ecn) {
    	if(RTTns<0) {
    		throw new IllegalArgumentException("RTT:"+ RTTns+" is negative!");
    	}
        // 处理ECN信号 - 将其视为强烈的拥塞信号
        if (ecn) {
            // 当收到ECN时，更激进地减少窗口
        	window2 = Math.max(0, window2 * 3 / 4);
            if (windowControlConsumer != null) {
                windowControlConsumer.accept(window2);
            }
        }
        
        // 更新最小RTT（BaseRTT）
        if (RTTns <= RTTMin) {
            RTTMin = RTTns;
        } else {
            // 缓慢适应：当网络路径真正变化时，BaseRTT应能缓慢更新
            // 这里使用极慢的衰减因子，只有在持续观测到更低RTT时才快速更新
            RTTMin = (RTTMin * 999 + RTTns) / 1000;
        }
        
        // 更新平滑RTT估计
        
            RTTVar = (RTTVar * 3 + Math.abs(RTTAvg - RTTns)) / 4;
            RTTAvg = (RTTAvg * 7 + RTTns) / 8;
        
        
        RTO = RTTAvg + Math.max(MIN_RTTVAR, RTTVar * 4);
        
        RTTTotal += RTTns;
        RTTCount++;
        
        long curr = System.nanoTime();
        // 每个RTT周期调整一次窗口（使用当前估计的RTT）
        if (curr - RTTstartTime > Math.max(BIAS, 2*RTTMin)) {
        	long RTTCountx=RTTCount;
            if (RTTCountx > 0) {
                long currentRTT = RTTTotal / RTTCountx;
                //RTTAvg2 = (RTTAvg2 * 3 + currentRTT) / 4;  // 平滑当前RTT
                RTTAvg2=currentRTT;
                RTTTotal = 0;
                RTTCount = 0;
            }
            
            // ================== Vegas2.0核心逻辑 ==================
            // 1. 计算时延膨胀比
            double delayRatio = (double) RTTAvg2 / (double) Math.max(BIAS, RTTMin);
            //System.out.println(delayRatio+" "+RTTAvg2/1000000.0+" "+RTTMin/1000000.0);
            // 2. 基于比值的窗口调整（取代原来的基于差值的调整）
            if (delayRatio > delayUpperBound) {
                // 时延过高：减小窗口，减少幅度与超标程度成正比
                window2 -= 4096;
            } else if (delayRatio < delayLowerBound) {
                // 时延过低：增大窗口，增加幅度与低于目标程度成正比
                window2 += 4096;
            } else {
              
            }
            // ===================================================
            
            
            
            
            updateWindowSize();
            RTTstartTime = curr;
            
            
            
            
        }
    }
    
	private void updateWindowSize() {
		// 窗口边界检查
        if (window2 >= maxwindow) {
        	window2 = maxwindow;
        }
        if (window2 < 0) {
        	window2 = 0;
        }
		// 速度计算：基于当前窗口和RTT，考虑一个安全边界
        // 使用目标膨胀比而非固定1.2倍，确保与窗口控制逻辑一致
        window=window2+MIN_WINDOW;
        
        if (windowControlConsumer != null) {
            windowControlConsumer.accept(window);
        }
	}

    @Override
    public void putLoss(long packetSize, long lossns, int losscounter) {
    }

    @Override
    public long getRTO() {
        return RTO;
    }

    @Override
    public void setCurrentWindowUsed(long used) {
        this.maxwindow = (long) (used * burstLimit )+ MIN_WINDOW;
    }

    @Override
    public void setCurrentBandwidth(long bandwidth) {
        // 可选：基于已知带宽信息调整参数
    }
    
    // 新增方法：获取当前状态信息（用于监控和调试）
    public double getCurrentDelayRatio() {
        return (double) RTTAvg2 / (double) Math.max(BIAS, RTTMin);
    }
    
    public long getBaseRTT() {
        return RTTMin;
    }
    
    public long getCurrentRTT() {
        return RTTAvg2;
    }

	@Override
	public void setUpperDelayBound(double upper) {
		delayUpperBound=upper;
	}

	@Override
	public void setLowerDelayBound(double lower) {
		delayLowerBound=lower;
	}

	@Override
	public void setBurstLimit(double limit) {
		burstLimit=limit;
	}
	@Override
	public String getName() {
		return "Vegas2";
	}

}