//
//  DefaultTransportFactory.swift
//  SignalRClient
//
//  Created by Pawel Kadluczka on 8/22/18.
//  Copyright © 2018 Pawel Kadluczka. All rights reserved.
//

import Foundation

internal class DefaultTransportFactory: TransportFactory {
    let logger: Logger
    let permittedTransportTypes: TransportType
    var orderOfPreference: [TransportType] = [.webSockets, .longPolling]
        
    init(logger: Logger, permittedTransportTypes: TransportType = .all) {
        self.logger = logger
        self.permittedTransportTypes = permittedTransportTypes
    }
    
    func createTransport(availableTransports: [TransportDescription]) throws -> Transport {
        let choices = determineAvailableTypes(availableTransports: availableTransports)
        let chosenType = chooseType(choices: choices, orderOfPreference: orderOfPreference)
        guard let transport = buildTransport(type: chosenType) else {
            throw SignalRError.noSupportedTransportAvailable
        }
        return transport
    }
    
    /// Builds the set of available transport types from the list of TransportDescriptions
    private func determineAvailableTypes(availableTransports: [TransportDescription]) -> TransportType {
        var choices: TransportType = .init()
        for transport in availableTransports {
            choices.formUnion(transport.transportType)
        }
        choices.formIntersection(permittedTransportTypes)
        return choices
    }
    
    /// Chooses a transport type from the supplied set of choices according to the supplied order of preference
    private func chooseType(choices: TransportType, orderOfPreference: [TransportType]) -> TransportType? {
        var chosen: TransportType? = nil
        for type in orderOfPreference {
            if choices.contains(type) {
                chosen = type
                break
            }
        }
        return chosen
    }
    
    /// Creates a Transport instance for the given (singular) transport type
    private func buildTransport(type: TransportType?) -> Transport? {
        if #available(OSX 10.15, iOS 13.0, watchOS 6.0, tvOS 13.0, *) {
            if type == .webSockets {
                logger.log(logLevel: .info, message: "Selected WebSockets transport")
                return WebsocketsTransport(logger: logger)
            }
        }
        if type == .longPolling {
            logger.log(logLevel: .info, message: "Selected LongPolling transport")
            return LongPollingTransport(logger: logger)
        }
        return nil
    }
}
