//
//  NonceGenerator.swift
//  punchnet
//
//  Created by 安礼成 on 2026/3/17.
//
import Foundation
import CryptoKit

/// ChaCha20-Poly1305 加解密示例
struct CCChaCha20Cipher: CCDataCipher {
    private let key: SymmetricKey
    private let nonceGenerator: NonceGenerator
    
    init(regionId: UInt32, keyData: Data) {
        self.key = SymmetricKey(data: keyData)
        self.nonceGenerator = NonceGenerator(regionId: regionId)
    }
    
    /// 加密
    func encrypt(plainText: Data) throws -> Data {
        let nonce = nonceGenerator.nextNonceData()
        let sealedBox = try ChaChaPoly.seal(plainText, using: key, nonce: .init(data: nonce))
        
        return sealedBox.combined
    }
    
    /// 解密
    func decrypt(cipherText: Data) throws -> Data {
        let sealedBox = try ChaChaPoly.SealedBox(combined: cipherText)
        return try ChaChaPoly.open(sealedBox, using: key)
    }
    
}

extension CCChaCha20Cipher {
    
    /// Nonce生成器（基于ServerRange + 毫秒时间低位 + 本地自增counter）
    final class NonceGenerator {
        private let locker = NSLock()
        
        private let regionId: UInt32          // 32-bit 全局前缀
        private var counter: UInt64 = 0          // 自增counter
        
        init(regionId: UInt32) {
            self.regionId = regionId
        }
        
        /// 生成64-bit Nonce
        func nextNonceData() -> Data  {
            locker.lock()
            defer {
                locker.unlock()
            }
            
            let nowMillis = UInt64(Date().timeIntervalSince1970 * 1000)
            // 时间占用40个bit位, 自增id占用24位
            let timeMask: UInt64 = (1 << 40) - 1
            let timeLow = nowMillis & timeMask
            
            // 生成 Nonce
            let counterMask: UInt64 = (1 << 24) - 1
            let nonce = (timeLow << 24) | (counter & counterMask)
            // 自增counter
            self.counter = (self.counter + 1) & counterMask // 超过最大值回到0
            
            var data = Data()
            // region: UInt32 -> 4字节大端
            data.append(contentsOf: withUnsafeBytes(of: regionId.bigEndian, Array.init))
            // nonce: UInt64 -> 8字节大端
            data.append(contentsOf: withUnsafeBytes(of: nonce.bigEndian, Array.init))
            
            return data
        }
    }
    
}
