package org.kne.cloud.clock;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;

import org.kne.math.Long128;

public class NTPTimestamps {

    // 常量定义
    public static final Long128 NANOS_PER_SECOND = Long128.valueOf(1_000_000_000L);
    public static final Long128 NANOS_PER_MILLIS = Long128.valueOf(1_000_000L);
    
    // NTP 纪元 (1900) 和 Unix 纪元 (1970) 之间的纳秒差
    public static final Long128 NTP_EPOCH_OFFSET_NS = Long128.valueOf(2208988800L)
                                                                 .multiply(NANOS_PER_SECOND);
    
    // 2^64 值，用于单位转换
    public static final Long128 TWO_POW_64 = Long128.ONE.shiftLeft(64);
    
    // 2^32 值，用于 64 位时间戳处理
    public static final Long128 TWO_POW_32 = Long128.ONE.shiftLeft(32);
    
    // 掩码常量
    public static final Long128 MASK_32_BIT = new Long128(0xFFFFFFFF);
    public static final Long128 MASK_64_BIT = new Long128(0xFFFFFFFFFFFFFFFFL);

    // ================== 核心转换方法 ==================
    // 2^32 秒，约 136.192 年，一个 NTP 纪元的长度
    public static final Long128 SECONDS_PER_ERA = Long128.valueOf(0x100000000L);
	private static final Long128 TWO_POW_N64_PER_NANOS = Long128.valueOf("1208925819614629");
    
    public static Long128 inferNtp64To128(long remote64Bit,Long128 local128Bit ) {
    	return inferNtp64To128(toUnsignedLong128(remote64Bit),local128Bit);
    }
   
    
    /**
     * 根据本地 128 位时间戳和网络 64 位时间戳，推断并补全纪元信息
     * 
     * @param remote64Bit 从网络接收的 64 位 NTP 时间戳
     * @param local128Bit 本地已知的 128 位 NTP 时间戳
     * @return 推断出的完整 128 位 NTP 时间戳
     */
    public static Long128 inferNtp64To128(Long128 remote64Bit,Long128 local128Bit ) {
        // 1. 从本地 128 位时间戳中提取纪元号和 64 位时间戳部分
        Long128 localEra = NTPTimestamps.getEraNumber(local128Bit);
        Long128 local64Bit = NTPTimestamps.getNtp64Timestamp(local128Bit);
        
        // 3. 计算本地和远程 64 位时间戳的差异
        Long128 difference = remote64Bit.subtract(local64Bit);
        
        // 4. 判断纪元关系并推断远程时间戳的纪元
        Long128 remoteEra;
        
        // 如果差异很大（超过半个纪元），可能需要调整纪元
        Long128 halfEra = Long128.valueOf(Long.MAX_VALUE);
        
        if (difference.compareTo(halfEra) > 0) {
            // 远程时间戳比本地小很多，可能属于上一个纪元
            remoteEra = localEra.subtract(Long128.ONE);
        } else if (difference.compareTo(halfEra.negate()) < 0) {
            // 远程时间戳比本地大很多，可能属于下一个纪元
            remoteEra = localEra.add(Long128.ONE);
        } else {
            // 差异不大，属于同一个纪元
            remoteEra = localEra;
        }
        
        // 5. 组合纪元号和 64 位时间戳，得到完整的 128 位时间戳
        return NTPTimestamps.ntp64To128(remote64Bit, remoteEra);
    }
    /**
     * 将从1970年开始的纳秒数转换为 NTPv4 128 位时间戳
     * 128位时间戳表示从1900年1月1日起经过的 2⁻⁶⁴ 秒的数量
     */
    public static Long128 nanosToNtp128BitTimestamp(Long128 nanosSince1970) {
        // 1. 计算从 1900 年开始的总纳秒数
        Long128 totalNanosFrom1900 = nanosSince1970.add(NTP_EPOCH_OFFSET_NS);

        // 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
      //  return totalNanosFrom1900.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
        return totalNanosFrom1900.multiply(TWO_POW_N64_PER_NANOS).shiftRight(16);
    }

    /**
     * 从 NTPv4 128 位时间戳转换回从1970年开始的纳秒数
     */
    public static Long128 ntp128BitToNanosTimestamp(Long128 ntp128Timestamp) {
        // 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
        Long128 totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
        
        // 2. 计算从 1970 年开始的总纳秒数
        return  totalNanosFrom1900.subtract(NTP_EPOCH_OFFSET_NS);
    }

    
    public static Long128 nanosToNtp128BitTimeInterval(Long128 nanos) {
        // 2. 将纳秒转换为 2⁻⁶⁴ 秒单位
        return nanos.multiply(TWO_POW_64).divide(NANOS_PER_SECOND);
    }

  
    public static Long128 ntp128BitToNanosInterval(Long128 ntp128Timestamp) {
        // 1. 将 2⁻⁶⁴ 秒单位转换回纳秒
        Long128 totalNanosFrom1900 = ntp128Timestamp.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
       
        return totalNanosFrom1900;
    }
    
    
    // ================== 128位 ↔ 64位 转换 ==================

    /**
     * 将 NTP 128 位时间戳转换为 NTP 64 位时间戳
     * 64位时间戳就是128位时间戳的中间64位
     */
    public static Long128 ntp128To64(Long128 ntp128Timestamp) {
        return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
    }

    /**
     * 将 NTP 64 位时间戳转换为 NTP 128 位时间戳
     * 64位时间戳放在128位时间戳的中间64位，高32位Era和低32位分数为0
     */
    public static Long128 ntp64To128(Long128 ntp64Timestamp) {
        return ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32);
    }

    /**
     * 将 NTP 64 位时间戳转换为 NTP 128 位时间戳（指定Era Number）
     */
    public static Long128 ntp64To128(Long128 ntp64Timestamp, Long128 eraNumber) {
        return eraNumber.and(MASK_32_BIT).shiftLeft(96)
               .or(ntp64Timestamp.and(MASK_64_BIT).shiftLeft(32));
    }

    /**
     * 从 NTP 128 位时间戳中提取 Era Number（高32位）
     */
    public static Long128 getEraNumber(Long128 ntp128Timestamp) {
        return ntp128Timestamp.shiftRight(96).and(MASK_32_BIT);
    }

    /**
     * 从 NTP 128 位时间戳中提取 64 位时间戳（中间64位）
     */
    public static Long128 getNtp64Timestamp(Long128 ntp128Timestamp) {
        return ntp128Timestamp.shiftRight(32).and(MASK_64_BIT);
    }

    /**
     * 从 NTP 128 位时间戳中提取分数部分（低32位）
     */
    public static Long128 getFraction(Long128 ntp128Timestamp) {
        return ntp128Timestamp.and(MASK_32_BIT);
    }

    // ================== 工具方法 ==================

    /**
     * 从毫秒和纳秒偏移构造 Long128 纳秒
     */
    public static Long128 toNanosSince1970(long unixTimeMillis, long nanosOffset) {
        return Long128.valueOf(unixTimeMillis)
                        .multiply( NANOS_PER_MILLIS)
                        .add(Long128.valueOf(nanosOffset));
    }

    /**
     * 从 Long128 纳秒提取毫秒和纳秒偏移
     */
    public static long[] toMillisAndNanos(Long128 nanosSince1970) {
    	Long128[] millisAndNanos = nanosSince1970.divideAndRemainder( NANOS_PER_MILLIS);
        return new long[]{millisAndNanos[0].longValue(), millisAndNanos[1].longValue()};
    }

    /**
     * 计算两个 128 位时间戳之间的时间差（纳秒）
     */
    public static Long128 calculateTimeDifference(Long128 timestamp1, Long128 timestamp2) {
        Long128 diff = timestamp2.subtract(timestamp1);
        return diff.multiply(NANOS_PER_SECOND).divide(TWO_POW_64);
    }

    

    /**
     * 将 64 位 NTP 时间戳分解为秒数和分数
     */
    public static Long128[] parseNtp64Timestamp(Long128 ntp64Timestamp) {
        Long128 seconds = ntp64Timestamp.shiftRight(32).and(MASK_32_BIT);
        Long128 fraction = ntp64Timestamp.and(MASK_32_BIT);
        return new Long128[]{seconds, fraction};
    }

    /**
     * 从秒数和分数构建 64 位 NTP 时间戳
     */
    public static Long128 buildNtp64Timestamp(Long128 seconds, Long128 fraction) {
        return seconds.and(MASK_32_BIT).shiftLeft(32).or(fraction.and(MASK_32_BIT));
    }

 
	
	 // 日期时间格式化器
   private static final DateTimeFormatter DEFAULT_FORMATTER = 
       DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.SSS");
   private static final DateTimeFormatter DETAILED_FORMATTER =
       DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss.n");
	public static String nanosSince1970ToString(Long128 nanos) {
		 Long128 millis = nanos.divide(Long128.valueOf(1_000_000));
		 Long128 nanosPart = nanos.mod(Long128.valueOf(1_000_000));
	        
	        Instant instant = Instant.ofEpochMilli(millis.longValue());
	        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
	        
	        return String.format("%s.%06d", 
	            DEFAULT_FORMATTER.format(dateTime),
	            nanosPart.longValue());
	}
	public static String nanosSince1970ToString2(Long128 nanos) {
		 Long128 millis = nanos.divide(Long128.valueOf(1_000_000));
	        
	        Instant instant = Instant.ofEpochMilli(millis.longValue());
	        LocalDateTime dateTime = LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
	        
	        return DEFAULT_FORMATTER.format(dateTime);
	}
	
	/**
     * 将 128 位时间戳转换为可读字符串
     */
    public static String ntp128ToString(Long128 ntp128Timestamp) {
    	Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp128Timestamp);
        return nanosSince1970ToString(nanosSince1970);
    }
    
    /**
     * 将 64 位时间戳转换为可读字符串
     */
    public static String ntp64ToString(Long128 ntp64Timestamp) {
    	Long128 nanosSince1970 = ntp128BitToNanosTimestamp(ntp64To128( ntp64Timestamp));
        return nanosSince1970ToString(nanosSince1970);
    }
    
    public static Long128 toUnsignedLong128(long unsignedLong) {
        if (unsignedLong >= 0) {
            return Long128.valueOf(unsignedLong);
        } else {
            // 对于负数，通过添加 2^64 来转换为无符号表示
            return Long128.valueOf(unsignedLong & 0x7FFFFFFFFFFFFFFFL)
                            .setBit(63);
        }
    }
}