package org.kne.cloud.clock;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.format.DateTimeFormatter;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.locks.ReentrantLock;

import org.kne.math.Long128;

public class HighAccuracyClock {
	
	
    private final long initialCPUNanoTime;
    private final Long128 initialSystemNanoTime;
    private volatile long baseCPUNanoTime;
    private volatile Long128 baseSystemNanoTime;
    
    private volatile long frequency=1000000000;//1000015000
    private volatile long frequency2=frequency*0xffffffffL/1000000000L;
    
	private ReentrantLock lock=new ReentrantLock();
	
    private static final Long128 NANOS_PER_MILLIS = Long128.valueOf(TimeUnit.MILLISECONDS.toNanos(1));
    

    private static final Long128 NANOS_PER_SECONDS = Long128.valueOf(TimeUnit.SECONDS.toNanos(1));
	public static final HighAccuracyClock SYSTEM_CLOCK = new HighAccuracyClock();
    
    
    public HighAccuracyClock() {
        this.initialSystemNanoTime =Long128.valueOf( System.currentTimeMillis() ).multiply(NANOS_PER_MILLIS);
        this.initialCPUNanoTime = System.nanoTime();
        this.baseSystemNanoTime=initialSystemNanoTime;
        this.baseCPUNanoTime=initialCPUNanoTime;
    }
    
    public long getFrequency() {
		return frequency;
	}

	public void setFrequency(long frequency) {
		lock.lock();
    	try {
    		long curr=System.nanoTime();
    		long nanoela=curr-baseCPUNanoTime;
    		baseCPUNanoTime=curr;
    		baseSystemNanoTime=baseSystemNanoTime.add( Long128.valueOf(nanoela).multiply(this.frequency).divide(NANOS_PER_SECONDS));
		this.frequency = frequency;
		this.frequency2=frequency*0xffffffffL/1000000000L;
    	}finally {
    		lock.unlock();
    	}
	}
	
	
	public void adjustFrequency(long fdelta) {
		lock.lock();
    	try {
    		compact();
		this.frequency = frequency+fdelta;
		this.frequency2=frequency*0xffffffffL/1000000000L;
    	}finally {
    		lock.unlock();
    	}
	}
	

	private void compact() {
		lock.lock();
    	try {
		long curr=System.nanoTime();
		long nanoela=curr-baseCPUNanoTime;
		baseCPUNanoTime=curr;
		baseSystemNanoTime=baseSystemNanoTime.add(Long128.valueOf(nanoela).multiply(this.frequency).divide(NANOS_PER_SECONDS));
    	}finally {
    		lock.unlock();
    	}
	}

	/**
     * 获取从1970-01-01开始的当前时间（纳秒精度）
     */
    public Long128 getCurrentTimeNanos() {
    	Long128 mul=Long128.valueOf(System.nanoTime()-baseCPUNanoTime).multiply(frequency2);
        return mul.shiftRight(32).add(baseSystemNanoTime);
    }
    
    /**
     * 获取从1970-01-01开始的当前时间（毫秒精度）
     */
    public long getCurrentTimeMillis() {
        return getCurrentTimeNanos().divide(NANOS_PER_MILLIS).longValue();
    }
    
    /**
     * 获取 NTPv4 128 位时间戳
     */
    public Long128 getCurrentTimeNTP128() {
        return NTPTimestamps.nanosToNtp128BitTimestamp(getCurrentTimeNanos());
    }
    
    /**
     * 获取 NTPv4 64 位时间戳
     */
    public Long128 getCurrentTimeNTP64() {
        return NTPTimestamps.ntp128To64(getCurrentTimeNTP128());
    }
    
    /**
     * 获取时钟创建以来经过的时间（纳秒）
     */
    public long getElapsedNanos() {
        return System.nanoTime() - initialCPUNanoTime;
    }
    
    // ================== 修复的时间同步方法 ==================
    
    /**
     * 强制同步到指定时间（正确版本）
     * @param targetNanos 目标时间（从1970年开始的纳秒数）
     */
    public void syncToTime(Long128 targetNanos) {
    	lock.lock();
    	try {
       baseCPUNanoTime= System.nanoTime();
       baseSystemNanoTime=targetNanos;
    	}finally {
    		lock.unlock();
    	}
    }
    
    /**
     * 基于参考时钟进行同步（更安全的方法）
     * @param referenceClock 参考时钟
     */
    public void syncToClock(HighAccuracyClock referenceClock) {
    	syncToClock(referenceClock,BigInteger.ZERO);
    }
    
    
    /**
     * 基于参考时钟进行同步（更安全的方法）
     * @param referenceClock 参考时钟
     * @param delta 网络延迟（纳秒），可选
     */
    public void syncToClock(HighAccuracyClock referenceClock, BigInteger delta) {
        if (delta == null) {
            delta = BigInteger.ZERO;
        }
        lock.lock();
    	try {
        baseCPUNanoTime=System.nanoTime();
        baseSystemNanoTime=referenceClock.getCurrentTimeNanos();
    	}finally {
    		lock.unlock();
    	}
    }
    
    /**
     * 基于NTP时间戳同步
     * @param ntp128Timestamp NTP 128位时间戳
     */
    public void syncToNTPTime(Long128 ntp128Timestamp) {
    	Long128 targetNanos = NTPTimestamps.ntp128BitToNanosTimestamp(ntp128Timestamp);
        syncToTime(targetNanos);
    }
    
    
    
    /**
     * 调整时钟（用于时间同步）
     * @param delta 要调整的纳秒数（正数调快，负数调慢）
     */
    public void adjustClock(Long128 delta) {
    	lock.lock();
    	try {
        baseSystemNanoTime = baseSystemNanoTime.add(delta);
    	}finally {
    		lock.unlock();
    	}
    }
    
    /**
     * 调整时钟（用于时间同步）
     * @param delta 要调整的纳秒数（正数调快，负数调慢）
     */
    public void adjustClock(Long128 delta, double adjPercent) {
        BigInteger adjustment=new BigDecimal(delta.toBigInteger()).multiply(BigDecimal.valueOf( adjPercent)).toBigInteger();
    	lock.lock();
    	try {
    		baseSystemNanoTime = baseSystemNanoTime.add(Long128 .valueOf(adjustment));
    	}finally {
    		lock.unlock();
    	}
    }
    
    
    
    /**
     * 获取时钟偏差（当前时间与真实时间的差异）
     */
    public Long128 getClockError(Long128 referenceTime) {
        return getCurrentTimeNanos().subtract(referenceTime);
    }
    
    /**
     * 检查时钟是否同步（误差在允许范围内）
     */
    public boolean isSynchronized(Long128 referenceTime, Long128 tolerance) {
    	Long128 error = getClockError(referenceTime).abs();
        return error.compareTo(tolerance) <= 0;
    }
    
    
 // ================== toString 方法 ==================
    
   
    
    /**
     * 转换为详细格式的字符串（包含纳秒）
     */
    public String toString() {
    	Long128 nanos = getCurrentTimeNanos();
       return NTPTimestamps.nanosSince1970ToString(nanos);
    }
    
    public String toString2() {
    	Long128 nanos = getCurrentTimeNanos();
        return NTPTimestamps.nanosSince1970ToString2(nanos);
	}

	public long getInitialCPUNanoTime() {
		return initialCPUNanoTime;
	}

	public Long128 getInitialSystemNanoTime() {
		return initialSystemNanoTime;
	}

	
    
    public static void main(String[] args) throws InterruptedException {
    	HighAccuracyClock hac=new HighAccuracyClock();
		while(true) {
			System.out.println(hac.getCurrentTimeNanos());
			Thread.sleep(1000);
		}
	}

	
    
   
}