import XCTest
@testable import Astro

class NavigationPluginTests: AstroTestCase {
    var messageBus: MessageBus!
    var pluginResolver: StubPluginResolver!
    var capture: RpcMethodResultCapture!
    var navigationPlugin: NavigationPlugin!

    override func setUp() {
        messageBus = MessageBus()
        pluginResolver = StubPluginResolver()
        capture = RpcMethodResultCapture()
        navigationPlugin = NavigationPlugin(address: "NavigationPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
    }

    func testNavigateToMultipleUrls() {
        let webViewPlugin = WebViewPlugin(address: "WebViewPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
        let webViewPlugin2 = WebViewPlugin(address: "WebViewPlugin:1", messageBus: self.messageBus, pluginResolver: self.pluginResolver, options: nil)
        pluginResolver.addPlugin(webViewPlugin)
        pluginResolver.addPlugin(webViewPlugin2)

        let options = JSONObject(dictionaryLiteral: ("animated", false))
        self.navigationPlugin.navigateToPlugin(webViewPlugin.address, options: options) { _ in }
        self.navigationPlugin.navigateToPlugin(webViewPlugin2.address, options: options) { _ in }
        XCTAssertEqual(self.navigationPlugin.typedViewController.viewControllers.count, 2, "There should two viewControllers currently stacked")
    }

    func correctNumberWebViewsPooled() {
        XCTAssertGreaterThan(PersistingNavigationController.maxTailViews, 3, "must be keeping at least the top 3 webview hydrated")
        XCTAssertGreaterThan(PersistingNavigationController.maxHeadViews, 0,
                             "must be keeping at leaset the root webview hydrated for popToRoot functionality to be smooth")
        XCTAssertEqual(PersistingNavigationController.maxHeadViews + PersistingNavigationController.maxTailViews,
                       PersistingNavigationController.maxViews,
                       "if this assumption changes, rehydration logic may have to be updated to rehydrate these other views we presumably want alive")

        let webViewPluginCount = 10
        var webViewPlugins = [WebViewPlugin]()
        for index in 0...webViewPluginCount {
            let webViewPlugin = WebViewPlugin(address: "WebViewPlugin:\(index)", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
            webViewPlugins.append(webViewPlugin)
            pluginResolver.addPlugin(webViewPlugin)
        }

        // Note: must call navigateToPlugin with animated = false in order to put multiple WebViews on the stack at once
        let options = JSONObject(dictionaryLiteral: ("animated", false))
        for webViewPlugin in webViewPlugins {
            navigationPlugin.navigateToPlugin(webViewPlugin.address, options: options) { _ in }
        }

        for index in 0...webViewPluginCount {
            if index < PersistingNavigationController.maxHeadViews || index > (webViewPluginCount - PersistingNavigationController.maxTailViews) {
                XCTAssertNotNil(webViewPlugins[index].typedViewController?.webView)
                XCTAssertNotNil(webViewPlugins[index].webViewAdaptor.getScrollViewFromWebView())
            } else {
                XCTAssertNil(webViewPlugins[index].typedViewController?.webView)
                XCTAssertNil(webViewPlugins[index].webViewAdaptor.getScrollViewFromWebView())
            }
        }

        XCTAssertEqual(self.navigationPlugin.typedViewController.viewControllers.count, webViewPluginCount + 1, "there are \(self.navigationPlugin.typedViewController.viewControllers.count) view controllers stacked instead of \(webViewPluginCount + 1)")
    }

    func testCorrectNumberWKWebViewsPooled() {
        correctNumberWebViewsPooled()
    }

    func testPopToRootNoWebViews() {
        expectAssertionWithDelay { expectation in
            self.navigationPlugin.popToRoot(animated: false, respond: CapturedRpcMethodResult.generateSuccessCallback { value in
                XCTAssertEqual(value as? NSNull, NSNull())
                expectation.fulfill()
            })
        }
    }
}
