//
//  SDLLayerPacketForwarder.swift
//  Tun
//
//  Created by 安礼成 on 2026/4/14.
//

import Foundation

struct SDLLayerPacketForwarder {
    
    enum DeliveryPlan {
        case superNode(payload: Data)
        case peer(payload: Data, session: Session)
        case superNodeAndPunch(payload: Data, request: SDLPuncherActor.RegisterRequest)
    }
    
    let networkAddress: SDLConfiguration.NetworkAddress
    let identityID: UInt32
    let dataCipher: CCDataCipher?
    let sessionManager: SessionManager
    
    func makeDeliveryPlan(dstMac: Data, type: LayerPacket.PacketType, data: Data) async throws -> DeliveryPlan? {
        guard let payload = try self.makePayload(dstMac: dstMac, type: type, data: data) else {
            return nil
        }
        
        if ARPPacket.isBroadcastMac(dstMac) {
            return .superNode(payload: payload)
        }
        
        if let session = await self.sessionManager.getSession(toAddress: dstMac) {
            return .peer(payload: payload, session: session)
        }
        
        return .superNodeAndPunch(
            payload: payload,
            request: .init(
                srcMac: self.networkAddress.mac,
                dstMac: dstMac,
                networkId: self.networkAddress.networkId
            )
        )
    }
    
    private func makePayload(dstMac: Data, type: LayerPacket.PacketType, data: Data) throws -> Data? {
        // 将数据封装层2层的数据包
        let layerPacket = LayerPacket(dstMac: dstMac, srcMac: self.networkAddress.mac, type: type, data: data)
        guard let dataCipher = self.dataCipher else {
            return nil
        }
        
        let encodedPacket = try dataCipher.encrypt(plainText: layerPacket.marshal())
        
        // 构造数据包
        var dataPacket = SDLData()
        dataPacket.networkID = self.networkAddress.networkId
        dataPacket.srcMac = self.networkAddress.mac
        dataPacket.dstMac = dstMac
        dataPacket.ttl = 255
        dataPacket.identityID = self.identityID
        dataPacket.isP2P = true
        dataPacket.data = encodedPacket
        
        return try dataPacket.serializedData()
    }
}
