import Foundation
import SystemConfiguration

public func connectedToNetwork() {
    
    var zeroAddress = sockaddr_in()
    zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
    zeroAddress.sin_family = sa_family_t(AF_INET)
    
    guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
        $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
            SCNetworkReachabilityCreateWithAddress(nil, $0)
        }
    }) else {
        print("Network Unreachable - Zero Address")
        return
    }
    
    var flags: SCNetworkReachabilityFlags = []
    if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
        print("Network Unreachable - Check Flags")
        return
    }
    
    let isReachable = flags.contains(.reachable)
    let needsConnection = flags.contains(.connectionRequired)
    connectedSpeed().testDownloadSpeedWithTimeout(5.0) { (megabytesPerSecond, error) in
        if error == nil && isReachable && !needsConnection {
            if let speed = megabytesPerSecond, speed >= 0.05 {
                print("\n       | Connected |")
                print("=======Network Speed=======\nMBps: \(speed)\nerror: \(String(describing: error))\n=======-------------=======\n")
            } else {
                print("\n       ? Connected ?")
                print("*======| WEAK SIGNAL |======*\nMBps: \(String(describing: megabytesPerSecond))\nerror: \(String(describing: error))\n*=======-------------=======*\n")
            }
        } else {
            print("NETWORK ERROR: \(String(describing: error))")
        }
    }
}

public class connectedSpeed: NSObject, URLSessionDelegate, URLSessionDataDelegate {
    
    var startTime: CFAbsoluteTime!
    var stopTime: CFAbsoluteTime!
    var bytesReceived: Int!
    var speedTestCompletionHandler: ((Double?, Error?) -> Void)!
    
    public func testDownloadSpeedWithTimeout(_ timeout: TimeInterval, completionHandler: @escaping (Double?, Error?) -> Void) {
        guard let url = URL(string: "https://wokaland.com/") else {
            completionHandler(nil, NSError(domain: "Invalid URL", code: -1, userInfo: nil))
            return
        }
        
        startTime = CFAbsoluteTimeGetCurrent()
        stopTime = startTime
        bytesReceived = 0
        speedTestCompletionHandler = completionHandler
        
        let configuration = URLSessionConfiguration.ephemeral
        configuration.timeoutIntervalForResource = timeout
        let session = URLSession(configuration: configuration, delegate: self, delegateQueue: nil)
        session.dataTask(with: url).resume()
    }
    
    public func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {
        bytesReceived += data.count
        stopTime = CFAbsoluteTimeGetCurrent()
    }
    
    public func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
        let elapsed = stopTime - startTime
        guard elapsed != 0 && (error == nil || (error as NSError?)?.domain == NSURLErrorDomain && (error as NSError?)?.code == NSURLErrorTimedOut) else {
            speedTestCompletionHandler(nil, error)
            return
        }
        
        let speed = elapsed != 0 ? Double(bytesReceived) / elapsed / 1024.0 / 1024.0 : -1
        speedTestCompletionHandler(speed, nil)
    }
}
