//
//  HeaderBarPluginTests.swift
//  Astro
//
//  Created by Mark Sandstrom on 6/30/15.
//  Copyright (c) 2015 Mobify Research & Development Inc. All rights reserved.
//

import XCTest
@testable import Astro

struct HeaderContentFactory {
    static func createHeaderContent(_ title: String = "Hello") -> HeaderContent {
        return HeaderContent(
            leftIcon: nil,
            centerIcon: HeaderContentItem(id: "title", content: .title(title), hidden: false, shouldFlipOnRTL: false),
            rightIcon: nil
        )
    }
}

class HeaderBarPluginTests: AstroTestCase {
    var messageBus: MessageBus!
    var capturedResult: CapturedRpcMethodResult!
    var pluginResolver: StubPluginResolver!

    override func setUp() {
        self.messageBus = MessageBus()
        self.capturedResult = CapturedRpcMethodResult()
        self.pluginResolver = StubPluginResolver()
    }

    func testHeaderBarDoesNotUpdateWhenSuspended() {
        let headerBar = HeaderBarPlugin(address: "HeaderBarPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
        headerBar.pushHeaderContent(HeaderContentFactory.createHeaderContent(), animated: false)
        headerBar.suspendUpdates()

        headerBar.setCenterTitle("Good Bye", id: "1", respond: capturedResult.callback)

        assertTitle("Hello", forHeaderBar: headerBar)
    }

    func testHeaderBarProcessesAllPendingUpdatesWhenResumed() {
        let headerBar = HeaderBarPlugin(address: "HeaderBarPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
        headerBar.pushHeaderContent(HeaderContentFactory.createHeaderContent(), animated: false)
        headerBar.suspendUpdates()

        headerBar.setCenterTitle("Good Bye", id: "1", respond: capturedResult.callback)

        assertTitle("Hello", forHeaderBar: headerBar)

        headerBar.resumeUpdates()

        while headerBar.updateQueue.operationCount > 0 {
            RunLoop.main.run(until: Date().addingTimeInterval(1.0))
        }

        assertTitle("Good Bye", forHeaderBar: headerBar)
    }

    func testHeaderBarAbortsAllPendingUpdatesWhenCancelled() {
        let headerBar = HeaderBarPlugin(address: "HeaderBarPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
        headerBar.pushHeaderContent(HeaderContentFactory.createHeaderContent(), animated: false)
        headerBar.suspendUpdates()

        headerBar.setCenterTitle("Good Bye", id: "1", respond: capturedResult.callback)

        assertTitle("Hello", forHeaderBar: headerBar)

        headerBar.discardPendingUpdatesAndResume()

        assertTitle("Hello", forHeaderBar: headerBar)
    }

    func assertTitle(_ title: String, forHeaderBar headerBar: HeaderBarPlugin) {
        // Urgh! Need to let the NSoperationQueue finish processing the queued operations
        flushRunLoop()

        if let navigationItems = headerBar.navigationBar.items,
            let lastItem = navigationItems.last,
            let currentTitle = lastItem.title {
                XCTAssertEqual(currentTitle, title)
        } else {
            XCTFail("Could not find last UINavigationItem or its title")
        }
    }

    func testHeaderBarSetOpaque() {
        let headerBar = HeaderBarPlugin(address: "HeaderBarPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
        headerBar.setOpaque(capturedResult.callback)
        XCTAssertFalse(headerBar.navigationBar.isTranslucent, "HeaderBar was not set opaque")
    }

    func testHeaderBarSetTranslucent() {
        let headerBar = HeaderBarPlugin(address: "HeaderBarPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
        headerBar.setTranslucent(capturedResult.callback)
        XCTAssertTrue(headerBar.navigationBar.isTranslucent, "HeaderBar was not set translucent")
    }

    func testKeepsNavigationStackInSyncWhenRemovingMiddleController() {
        let headerBar = HeaderBarPlugin(address: "HeaderBarPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)

        // Note that the HeaderBar implicitly has one navigation stack item when
        // you create it. And so pushing three times results in 4 items on the 
        // navigation stack!
        headerBar.pushHeaderContent(HeaderContentFactory.createHeaderContent("Two"), animated: false)
        headerBar.pushHeaderContent(HeaderContentFactory.createHeaderContent("Three"), animated: false)
        headerBar.pushHeaderContent(HeaderContentFactory.createHeaderContent("Four"), animated: false)

        let totalCount = headerBar.navigationItems.count

        // [ One (implicit) ][Two][Three][Four]
        //    0                1     2      3
        headerBar.removeHeaderContentAtIndex(2) // "Three"

        AssertEqual(headerBar.headerContentStack.count, b: totalCount - 1)
        AssertEqual(headerBar.navigationBar.items!.count, b: totalCount - 1)
    }
}
