//
//  FlowSessionTable.swift
//  punchnet
//  tcp/udp Flow流管理
//  Created by 安礼成 on 2026/3/10.
//
import Foundation

// MARK: - 五元组 key
struct FlowSession: Hashable {
    let srcIP: UInt32
    let dstIP: UInt32
    let srcPort: UInt16
    let dstPort: UInt16
    let proto: UInt8

    func hash(into hasher: inout Hasher) {
        // 高效组合 hash
        hasher.combine(srcIP)
        hasher.combine(dstIP)
        hasher.combine(UInt32(srcPort) << 16 | UInt32(dstPort))
        hasher.combine(proto)
    }

    static func ==(lhs: Self, rhs: Self) -> Bool {
        return lhs.srcIP == rhs.srcIP &&
               lhs.dstIP == rhs.dstIP &&
               lhs.srcPort == rhs.srcPort &&
               lhs.dstPort == rhs.dstPort &&
               lhs.proto == rhs.proto
    }

    func reverse() -> FlowSession {
        return FlowSession(
            srcIP: dstIP,
            dstIP: srcIP,
            srcPort: dstPort,
            dstPort: srcPort,
            proto: proto
        )
    }

}

// MARK: - 会话表
final class FlowSessionTable: @unchecked Sendable {
    private var sessions: [FlowSession: TimeInterval] = [:]
    private let lock = NSLock()
    private let sessionTimeout: TimeInterval

    /// - Parameter sessionTimeout: 会话闲置多久（秒）被清理
    init(sessionTimeout: TimeInterval = 300) {
        self.sessionTimeout = sessionTimeout
    }

    // 插入或更新会话
    func updateSession(_ key: FlowSession) {
        lock.lock()
        defer {
            lock.unlock()
        }
        sessions[key] = Date().timeIntervalSince1970 + sessionTimeout
    }
    
    // 查找会话
    func hasSession(_ key: FlowSession) -> Bool {
        lock.lock()
        defer {
            lock.unlock()
        }

        if let expireTs = sessions[key] {
            if expireTs >= Date().timeIntervalSince1970 {
                return true
            }
            self.sessions.removeValue(forKey: key)
        }

        return false
    }

    // 删除会话
    func removeSession(_ key: FlowSession) {
        lock.lock()
        defer {
            lock.unlock()
        }
        
        sessions.removeValue(forKey: key)
    }

    func clear() {
        lock.lock()
        defer {
            lock.unlock()
        }

        sessions.removeAll()
    }

    // 清理过期会话
    func cleanupExpiredSessions() {
        lock.lock()
        defer {
            lock.unlock()
        }
        
        let now = Date().timeIntervalSince1970
        self.sessions = self.sessions.filter { $0.value >= now }
    }

    // 返回当前会话数（调试/统计用）
    var count: Int {
        lock.lock()
        defer {
            lock.unlock()
        }
        return sessions.count
    }
    
}

extension IPPacket {
    
    func flowSession() -> FlowSession? {
        switch self.transportPacket {
        case .tcp(let tcpPacket):
            return FlowSession(srcIP: header.source, dstIP: header.destination, srcPort: tcpPacket.header.srcPort, dstPort: tcpPacket.header.dstPort, proto: header.proto)
        case .udp(let udpPacket):
            return FlowSession(srcIP: header.source, dstIP: header.destination, srcPort: udpPacket.srcPort, dstPort: udpPacket.dstPort, proto: header.proto)
        default:
            return nil
        }
    }
}

extension IPPacketView {

    func flowSession() -> FlowSession? {
        switch self.transportPacket {
        case .tcp(let srcPort, let dstPort):
            return FlowSession(srcIP: header.source, dstIP: header.destination, srcPort: srcPort, dstPort: dstPort, proto: header.proto)
        case .udp(let srcPort, let dstPort, _):
            return FlowSession(srcIP: header.source, dstIP: header.destination, srcPort: srcPort, dstPort: dstPort, proto: header.proto)
        default:
            return nil
        }
    }
}
