//
//  IdentityStore.swift
//  punchnet
//  1. 需要增加规则基于轮训更新的逻辑
//  Created by 安礼成 on 2026/2/5.
//
import Foundation
import NIO

actor IdentityStore {
    
    // 处理权限的请求问题
    nonisolated private let cooldown: Duration = .seconds(5)
    // identityId
    private var coolingDown: Set<UInt32> = []
    // 处理各个请求的版本问题, map[identityId] = version
    private var versions: [UInt32: UInt32] = [:]
    
    nonisolated private let alloctor = ByteBufferAllocator()
    
    private let publisher: SnapshotPublisher<IdentitySnapshot>
    private var identityMap: [UInt32: IdentityRuleMap] = [:]
    
    init(publisher: SnapshotPublisher<IdentitySnapshot>) {
        self.publisher = publisher
    }
    
    // 批量更新, 有外部任务驱动，因为这里依赖于当前的quicClient
    func batUpdatePolicy(using quicClient: SDLQUICClient?, dstIdentityID: UInt32) {
        guard let quicClient else {
            return
        }
        
        self.identityMap.keys.forEach { identityId in
            var policyRequest = SDLPolicyRequest()
            policyRequest.srcIdentityID = identityId
            policyRequest.dstIdentityID = dstIdentityID
            policyRequest.version = self.nextVersion(identityId: identityId)
            
            // 发送请求
            if let queryData = try? policyRequest.serializedData() {
                quicClient.send(type: .policyRequest, data: queryData)
            }
        }
    }
    
    // 提交权限请求
    func policyRequest(srcIdentityId: UInt32, dstIdentityId: UInt32, using quicClient: SDLQUICClient?) {
        guard let quicClient, !coolingDown.contains(srcIdentityId) else {
            return
        }
        
        var policyRequest = SDLPolicyRequest()
        policyRequest.srcIdentityID = srcIdentityId
        policyRequest.dstIdentityID = dstIdentityId
        policyRequest.version = self.nextVersion(identityId: srcIdentityId)
        
        // 触发一次打洞
        coolingDown.insert(srcIdentityId)
        // 发送请求
        if let queryData = try? policyRequest.serializedData() {
            quicClient.send(type: .policyRequest, data: queryData)
        }
        
        Task {
            // 启动冷却期
            try? await Task.sleep(for: .seconds(5))
            self.endCooldown(for: srcIdentityId)
        }
    }
    
    // 处理权限的响应
    func applyPolicyResponse(_ policyResponse: SDLPolicyResponse) {
        let id = policyResponse.srcIdentityID
        let version = policyResponse.version
        
        guard self.identityMap[id] == nil || ((self.identityMap[id]?.version ?? 0) < version) else {
            return
        }
        
        // 判断一下是否接受完成
        var buffer = alloctor.buffer(bytes: policyResponse.rules)
        var ruleMap: [UInt8: [UInt16: Bool]] = [:]
        while true {
            guard let proto = buffer.readInteger(endianness: .big, as: UInt8.self),
                  let port = buffer.readInteger(endianness: .big, as: UInt16.self) else {
                break
            }
            ruleMap[proto, default: [:]][port] = true
        }
        self.identityMap[id] = IdentityRuleMap(version: version, ruleMap: ruleMap)
        
        // 发布新的快照信息
        let snapshot = compileSnapshot()
        publisher.publish(snapshot)
    }
    
    private func compileSnapshot() -> IdentitySnapshot {
        return IdentitySnapshot(identityMap: identityMap)
    }

    private func endCooldown(for key: UInt32) {
        self.coolingDown.remove(key)
    }
    
    private func nextVersion(identityId: UInt32) -> UInt32 {
        let version = self.versions[identityId, default: 1]
        // 更新请求的版本问题
        self.versions[identityId] = version + 1
        
        return version
    }
}
