//
//  LayerPacket.swift
//  Tun
//
//  Created by 安礼成 on 2024/8/21.
//

import Foundation
import zlib

struct LayerPacket {
    // 数据包类型
    enum PacketType: UInt16 {
        case arp = 0x0806
        case ipv4 = 0x0800
        case ipv6 = 0x86DD
        case taggedFrame = 0x8100
    }
    
    enum LayerPacketError: Error {
        case invalidLength
        case invaldPacketType
    }
    
    struct MacAddress {
        let data: Data
        
        init(data: Data) {
            self.data = data
        }
        
        func isBroadcast() -> Bool {
            return data.count == 6 && self.data.allSatisfy { $0 == 0xFF}
        }
        
        func isMulticast() -> Bool {
            return data.count == 6 && (data[0] == 0x01 && data[1] == 0x00 && data[2] == 0x5E)
        }
        
        func format() -> String {
            // 将mac地址转换成字符串
            let bytes = [UInt8](data)
            return bytes.map { String(format: "%02X", $0) }.joined(separator: ":").lowercased()
        }
        
        static func description(data: Data) -> String {
            // 将mac地址转换成字符串
            let bytes = [UInt8](data)
            return bytes.map { String(format: "%02X", $0) }.joined(separator: ":").lowercased()
        }
        
    }
    
    let dstMac: Data
    let srcMac: Data
    let type: PacketType
    let data: Data
    
    init(dstMac: Data, srcMac: Data, type: PacketType, data: Data) {
        self.dstMac = dstMac
        self.srcMac = srcMac
        self.type = type
        self.data = data
    }
    
    init(layerData playload: Data) throws {
        guard playload.count >= 14 else {
            throw LayerPacketError.invalidLength
        }
        
        self.dstMac = Data(playload[0..<6])
        self.srcMac = Data(playload[6..<12])
        guard let type = PacketType(rawValue: UInt16(bytes: (playload[12], playload[13]))) else {
            throw LayerPacketError.invaldPacketType
        }
        
        self.type = type
        self.data = Data(playload[14...])
    }
    
    func marshal() -> Data {
        var packet = Data(capacity: 14 + self.data.count)
        packet.append(dstMac)
        packet.append(srcMac)
        packet.append(UInt8(self.type.rawValue >> 8))
        packet.append(UInt8(self.type.rawValue & 0x00FF))
        packet.append(self.data)
        
        return packet
    }
    
    private static func crc32(data: Data) -> UInt32 {
        let crc = data.withUnsafeBytes { buffer in
            return zlib.crc32(0, buffer.bindMemory(to: UInt8.self).baseAddress, uInt(buffer.count))
        }
        
        return UInt32(crc)
    }
    
}

struct LayerPacketView {
    let type: LayerPacket.PacketType
    let data: Data

    init(layerData payload: Data) throws {
        guard payload.count >= 14 else {
            throw LayerPacket.LayerPacketError.invalidLength
        }

        guard let type = LayerPacket.PacketType(rawValue: UInt16(bytes: (payload[12], payload[13]))) else {
            throw LayerPacket.LayerPacketError.invaldPacketType
        }

        self.type = type
        self.data = payload.dropFirst(14)
    }
}
