//
//  ArpServer.swift
//  sdlan
//  1. 通过ip地址查找mac地址
//  2. 要限制单位时间内，同一个ip的查询
//  Created by 安礼成 on 2025/7/14.
//
import Foundation
import Darwin

actor ArpServer {
    // 增加缓存时间逻辑
    struct ArpEntry {
        var mac: Data
        var expireTime: TimeInterval
    }
    
    private var coolingDown: [UInt32: Date] = [:]
    
    private var known_macs: [UInt32: ArpEntry] = [:]
    private let arpTTL: TimeInterval
    
    private var cleanupTask: Task<Void, Never>?
    
    init(arpTTL: TimeInterval = 300) {
        self.arpTTL = arpTTL
    }
    
    func start() {
        guard self.cleanupTask == nil else {
            return
        }
        
        self.cleanupTask = Task {
            while !Task.isCancelled {
                try? await Task.sleep(for: .seconds(1))
                self.cleanup()
            }
        }
    }
    
    func query(ip: UInt32) -> Data? {
        guard let entry = known_macs[ip] else {
            return nil
        }
        
        if entry.expireTime < Date().timeIntervalSince1970 {
            known_macs.removeValue(forKey: ip)
            return nil
        }
        
        return entry.mac
    }
    
    func append(ip: UInt32, mac: Data) {
        let expireAt = Date().timeIntervalSince1970 + arpTTL
        self.known_macs[ip] = ArpEntry(mac: mac, expireTime: expireAt)
    }
    
    func remove(ip: UInt32) {
        self.known_macs.removeValue(forKey: ip)
    }
    
    func dropMacs(macs: [Data]) {
        self.known_macs = self.known_macs.filter { !macs.contains($0.value.mac) }
    }
    
    func clear() {
        self.known_macs = [:]
        self.coolingDown = [:]
    }
    
    func arpRequest(targetIp: UInt32, use quicClient: SDLQUICClient?) async throws {
        guard let quicClient, self.coolingDown[targetIp] == nil else {
            return
        }
        
        // 单位时间内指允许提交一次
        self.coolingDown[targetIp] = Date().addingTimeInterval(3)
        
        // 进行arp查询
        var arpRequest = SDLArpRequest()
        arpRequest.targetIp = targetIp
        
        await quicClient.send(type: .arpRequest, data: try arpRequest.serializedData())
    }
    
    func handleArpResponse(arpResponse: SDLArpResponse) {
        let targetIp = arpResponse.targetIp
        let targetMac = arpResponse.targetMac
        if !targetMac.isEmpty {
            let expireAt = Date().timeIntervalSince1970 + arpTTL
            self.known_macs[targetIp] = ArpEntry(mac: targetMac, expireTime: expireAt)
        }
    }
    
    private func cleanup() {
        let now = Date()
        self.coolingDown = self.coolingDown.filter { $0.value > now }
    }
    
    deinit {
        self.cleanupTask?.cancel()
    }
    
}
