//
//  Session.swift
//  sdlan
//  Session是增加了有效时间的
//  Created by 安礼成 on 2025/7/14.
//
import Foundation
import NIOCore
import Darwin

struct Session {
    enum AddressType: String, Hashable {
        case v4
        case v6
    }

    // 在内部的通讯的ip地址, 整数格式
    let dstMac: Data
    // 对端的主机在nat上映射的端口信息
    let natAddress: SocketAddress
    // 当前会话对应的外层地址族
    let addressType: AddressType
    
    // 最后使用时间
    var lastTimestamp: Int32
    
    init?(dstMac: Data, natAddress: SocketAddress, addressType: AddressType) {
        self.dstMac = dstMac
        self.natAddress = natAddress
        self.addressType = addressType
        self.lastTimestamp = Int32(Date().timeIntervalSince1970)
    }

    mutating func updateLastTimestamp(_ lastTimestamp: Int32) {
        self.lastTimestamp = lastTimestamp
    }
}

actor SessionManager {
    private var sessions: [Data: [Session.AddressType: Session]] = [:]
    
    // session的有效时间
    private let ttl: Int32 = 10
    
    func getSession(toAddress: Data) -> Session? {
        let timestamp = Int32(Date().timeIntervalSince1970)
        
        guard var peerSessions = self.sessions[toAddress] else {
            return nil
        }
        
        peerSessions = peerSessions.filter { $0.value.lastTimestamp + ttl >= timestamp }
        guard !peerSessions.isEmpty else {
            self.sessions.removeValue(forKey: toAddress)
            return nil
        }
        
        guard var session = self.selectSession(in: peerSessions) else {
            self.sessions[toAddress] = peerSessions
            return nil
        }
        
        session.updateLastTimestamp(timestamp)
        peerSessions[session.addressType] = session
        
        self.sessions[toAddress] = peerSessions
        
        return session
    }

    func addSession(session: Session) {
        let timestamp = Int32(Date().timeIntervalSince1970)
        
        var sessions = self.sessions[session.dstMac, default: [:]]
        sessions = sessions.filter {
            $0.value.lastTimestamp + ttl >= timestamp && $0.key != session.addressType
        }
        sessions[session.addressType] = session
        
        self.sessions[session.dstMac] = sessions
    }
    
    func removeSession(dstMac: Data) {
        self.sessions.removeValue(forKey: dstMac)
    }
    
    func clear() {
        self.sessions.removeAll()
    }

    private func selectSession(in sessions: [Session.AddressType: Session]) -> Session? {
        return sessions.values.max(by: { $0.lastTimestamp < $1.lastTimestamp })
    }
    
}
