import Foundation
import Network
import WebRTC

enum ExternalServiceTransport: String, Stateable {
    case tcp
    case udp
}

struct ExternalService: Stateable {
    let host: String
    let name: String?
    let password: String?
    let port: UInt16?
    let restricted: Bool
    let transport: ExternalServiceTransport?
    let type: String
    let username: String?

    init(type: String, host: String, port: UInt16? = nil, transport: ExternalServiceTransport? = nil, name: String? = nil, restricted: Bool = false, username: String? = nil, password: String? = nil) {
        self.type = type
        self.host = host
        self.port = port
        self.transport = transport
        self.name = name
        self.restricted = restricted
        self.username = username
        self.password = password
    }

    public static func parse(_ element: XMLElement) -> ExternalService? {
        guard element.name == "service", let type = element.attributes["type"], let host = element.attributes["host"] else {
            return nil
        }
        let transport = ExternalServiceTransport(rawValue: element.attributes["transport"]?.lowercased() ?? "tcp") ?? .tcp
        let restrictedStr = element.attributes["restricted"]
        var port: UInt16?
        if let portStr = element.attributes["port"] {
            port = UInt16(portStr)
        }
        return ExternalService(
            type: type,
            host: host,
            port: port,
            transport: transport, name: element.attributes["name"],
            restricted: restrictedStr == "1" || restrictedStr == "true",
            username: element.attributes["username"],
            password: element.attributes["password"]
        )
    }
}

extension ExternalService {
    func asRTCIceServer() -> RTCIceServer? {
        guard ["stun", "stuns", "turn", "turns"].contains(type) else { return nil }
        guard !type.hasSuffix("s") || transport == .tcp else { return nil }
        guard !type.hasPrefix("turn") || username != nil else { return nil }

        let url = urlString()
        return RTCIceServer(urlStrings: [url], username: username, credential: password, tlsCertPolicy: .insecureNoCheck)
    }

    private func urlString() -> String {
        let host = escapedHost()

        var result = "\(type):\(host)"
        if let port {
            result += ":\(port)"
        }
        return result
    }

    private func escapedHost() -> String {
        if #available(iOS 12.0, *) {
            return IPv6Address(host) != nil ? "[\(host)]" : host
        } else {
            return host.contains(":") && !(host.hasPrefix("[") || host.hasSuffix("]")) ? "[\(host)]" : host
        }
    }
}
