//
//  SDLConfiguration.swift
//  sdlan
//
//  Created by 安礼成 on 2025/7/14.
//
import Foundation
import NIOCore

// 配置项目
public class SDLConfiguration {
    
    // 网络地址信息
    public struct NetworkAddress {
        public let networkId: UInt32
        public let ip: UInt32
        public let maskLen: UInt8
        public let mac: Data
        public let networkDomain: String
        
        // ip地址
        var ipAddress: String {
            return SDLUtil.int32ToIp(self.ip)
        }
        
        // 掩码
        var maskAddress: String {
            let len0 = 32 - maskLen
            let num: UInt32 = (0xFFFFFFFF >> len0) << len0
            
            return SDLUtil.int32ToIp(num)
        }
        
        // 网络地址
        var netAddress: String {
            let len0 = 32 - maskLen
            let mask: UInt32 = (0xFFFFFFFF >> len0) << len0
            
            return SDLUtil.int32ToIp(self.ip & mask)
        }
    }
    
    // 网络出口
    public struct ExitNode {
        let exitNodeIp: UInt32
    }

    // 解析的服务器地址信息
    public struct ResolvedServerEndpoint: Sendable {
        let host: String
        let ip: String
    }
    
    // 当前的客户端版本
    let version: Int
    
    let serverEndpoint: ResolvedServerEndpoint

    let stunSocketAddress: SocketAddress

    // 网络探测地址信息
    let stunProbeSocketAddressArray: [[SocketAddress]]
    
    let clientId: String
    let networkAddress: NetworkAddress
    let hostname: String
    let accessToken: String
    let identityId: UInt32
    
    var exitNode: ExitNode?
    
    public init(version: Int,
                serverEndpoint: ResolvedServerEndpoint,
                stunServers: [String],
                clientId: String,
                networkAddress: NetworkAddress,
                hostname: String,
                accessToken: String,
                identityId: UInt32,
                exitNode: ExitNode?) {
        self.version = version
        self.serverEndpoint = serverEndpoint
        let stunHosts = stunServers.isEmpty ? [serverEndpoint.ip] : stunServers
        self.stunSocketAddress = Self.makeStunSocketAddress(host: stunHosts[0], port: 1365)
        self.stunProbeSocketAddressArray = stunHosts.map { stunServer in
            [
                Self.makeStunSocketAddress(host: stunServer, port: 1365),
                Self.makeStunSocketAddress(host: stunServer, port: 1366)
            ]
        }
        self.clientId = clientId
        self.networkAddress = networkAddress
        self.accessToken = accessToken
        self.identityId = identityId
        self.hostname = hostname
        self.exitNode = exitNode
    }
    
}

private extension SDLConfiguration {

    static func resolveHostAddress(host: String, port: Int) -> String {
        let address = try! SocketAddress.makeAddressResolvingHost(host, port: port)
        return address.ipAddress!
    }

    static func makeStunSocketAddress(host: String, port: Int) -> SocketAddress {
        return try! SocketAddress.makeAddressResolvingHost(host, port: port)
    }

}

// 解析配置文件
extension SDLConfiguration {
    
    static func parse(options: [String: NSObject]) -> SDLConfiguration? {
        guard let version = options["version"] as? Int,
              let serverHost = options["server_host"] as? String,
              let stunAssistHost = options["stun_assist_host"] as? String,
              let accessToken = options["access_token"] as? String,
              let identityId = options["identity_id"] as? UInt32,
              let clientId = options["client_id"] as? String,
              let hostname = options["hostname"] as? String,
              let networkAddressDict = options["network_address"] as? [String: NSObject] else {
            return nil
        }
        
        guard let networkAddress = parseNetworkAddress(networkAddressDict) else {
            return nil
        }
        
        // 网络出口配置是可选的
        var exitNode: ExitNode? = nil
        if let exitNodeIpStr = options["exit_node_ip"] as? String, let exitNodeIp = SDLUtil.ipv4StrToInt32(exitNodeIpStr) {
            exitNode = .init(exitNodeIp: exitNodeIp)
        }

        let serverEndpoint = ResolvedServerEndpoint(
            host: serverHost,
            ip: Self.resolveHostAddress(host: serverHost, port: 1443)
        )
        
        return SDLConfiguration(version: version,
                                serverEndpoint: serverEndpoint,
                                stunServers: [serverHost, stunAssistHost],
                                clientId: clientId,
                                networkAddress: networkAddress,
                                hostname: hostname,
                                accessToken: accessToken,
                                identityId: identityId,
                                exitNode: exitNode)
    }
    
    private static func parseNetworkAddress(_ config: [String: NSObject]) -> SDLConfiguration.NetworkAddress? {
        guard let networkId = config["network_id"] as? UInt32,
              let ipStr = config["ip"] as? String,
              let ip = SDLUtil.ipv4StrToInt32(ipStr),
              let maskLen = config["mask_len"] as? UInt8,
              let mac = config["mac"] as? Data,
              let networkDomain = config["network_domain"] as? String else {
            return nil
        }
        
        return .init(networkId: networkId, ip: ip, maskLen: maskLen, mac: mac, networkDomain: networkDomain)
    }
    
}
