//
//  Copyright (c) 2015 Mobify Research & Development Inc. All rights reserved.
//

import XCTest
@testable import Astro

class TabBarPluginTests: AstroTestCase {
    var messageBus: MessageBus!
    var pluginResolver: StubPluginResolver!

    var tabBarPlugin: TabBarPlugin!
    var tabBar: UITabBar!
    var respond: CapturedRpcMethodResult!

    override func setUp() {
        messageBus = MessageBus()
        pluginResolver = StubPluginResolver()

        tabBarPlugin = TabBarPlugin(address: "TabBarPlugin:0", messageBus: messageBus, pluginResolver: pluginResolver, options: nil)
        tabBar = tabBarPlugin.viewController.view.subviews.first?.subviews.first as! UITabBar
        respond = CapturedRpcMethodResult()
    }

    func testSetBackgroundColor() {
        tabBarPlugin.setBackgroundColor("#0000FF") { _ in }

        XCTAssertEqual(tabBar.barTintColor!, UIColor.blue)
    }

    func testSetColor() {
        tabBarPlugin.setColor("#0000FF", inactiveColor: "#FF0000") { _ in }

        XCTAssertEqual(tabBar.tintColor!, UIColor.blue)
        let titleTextAttributes = convertFromOptionalNSAttributedStringKeyDictionary(UITabBarItem.appearance().titleTextAttributes(for: .normal))!
        XCTAssertEqual(titleTextAttributes[NSAttributedString.Key.foregroundColor.rawValue] as? UIColor, UIColor.red)
    }

    func testSetInactiveColorWithPreviousAppearance() {
        UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.font: UIFont(name: "IowanOldStyle-Bold", size: 10.0)!], for: .normal)
        tabBarPlugin.setColor("#0000FF", inactiveColor: "#FF0000") { _ in }

        XCTAssertEqual(tabBar.tintColor!, UIColor.blue)
        let titleTextAttributes = convertFromOptionalNSAttributedStringKeyDictionary(UITabBarItem.appearance().titleTextAttributes(for: .normal))!
        XCTAssertEqual(titleTextAttributes[NSAttributedString.Key.foregroundColor.rawValue] as? UIColor, UIColor.red)
        XCTAssertEqual((titleTextAttributes[NSAttributedString.Key.font.rawValue] as! UIFont).fontName, "IowanOldStyle-Bold")
    }

    func testSetOpaque() {
        tabBarPlugin.setOpaque()

        XCTAssertEqual(tabBar.isTranslucent, false)
    }

    func testSetTranslucent() {
        tabBarPlugin.setTranslucent()

        XCTAssertEqual(tabBar.isTranslucent, true)
    }

    func createTabBarItemMetadataJson(id: String? = "id", title: String? = "title", imageUrl: String? = "file:///astro-logo.png", selectedImageUrl: String? = "file:///astro-logo.png") -> JSONObject {

        var metadataJson = JSONObject()

        if let id = id {
            metadataJson["id"] = id
        }
        if let title = title {
            metadataJson["title"] = title
        }
        if let imageUrl = imageUrl {
            metadataJson["imageUrl"] = imageUrl
        }
        if let selectedImageUrl = selectedImageUrl {
            metadataJson["selectedImageUrl"] = selectedImageUrl
        }

        return metadataJson
    }

    func testTabBarItemMetadataFromJsonSuccessful() {
        let metadataJson = createTabBarItemMetadataJson(id: "id", title: "title")
        let metadata = TabBarPlugin.TabBarItemMetadata.fromJson(metadataJson, respond: respond.callback)

        if !respond.hasError, let metadata = metadata {
            XCTAssertEqual(metadata.id, "id")
            XCTAssertEqual(metadata.title, "title")
            XCTAssertNotNil(metadata.image)
            XCTAssertNotNil(metadata.selectedImage)
        } else {
            XCTAssertTrue(false, "Could not parse metadata: " + (respond.error ?? ""))
        }
    }

    func testTabBarItemMetadataFromJsonFailure() {
        let metadataJsons = [
            JSONObject(),
            createTabBarItemMetadataJson(id: nil),
            createTabBarItemMetadataJson(title: nil),
            createTabBarItemMetadataJson(imageUrl: nil),
            createTabBarItemMetadataJson(selectedImageUrl: nil),
            createTabBarItemMetadataJson(imageUrl: "file:///some_invalid_filename.png"),
            createTabBarItemMetadataJson(selectedImageUrl: "file:///some_invalid_filename.png")
        ]

        for metadataJson in metadataJsons {
            let metadata = TabBarPlugin.TabBarItemMetadata.fromJson(metadataJson, respond: respond.callback)
            XCTAssert(respond.hasError)
            AssertNil(metadata)
        }
    }

    func testSetItems() {
        let metadataJsons = [
            createTabBarItemMetadataJson(id: "home", title: "Home"),
            createTabBarItemMetadataJson(id: "favourites", title: "Favourites"),
            createTabBarItemMetadataJson(id: "cart", title: "Cart"),
            createTabBarItemMetadataJson(id: "settings", title: "Settings")
        ]

        tabBarPlugin.setItems(metadataJsons, respond: respond.callback)

        guard let items = tabBar.items else {
            XCTFail("Expected the tabbar to have items, but there are no items (tabBar.items returned nil) in the tabbar")
            return
        }

        XCTAssertEqual(items.count, metadataJsons.count)

        if let tabBarItems = tabBar.items {
            for (index, tabBarItem) in tabBarItems.enumerated() {
                let metadataJson = metadataJsons[index]
                XCTAssertEqual(tabBarItem.title!, metadataJson["title"]! as! String)
                XCTAssertNotNil(tabBarItem.image)
                XCTAssertNotNil(tabBarItem.selectedImage)
            }
        }

        XCTAssertEqual(tabBar.selectedItem!.title!, "Home")
    }

    func testSetItemsRestoresSelectedItem() {
        let homeMetadataJson = createTabBarItemMetadataJson(id: "home", title: "Home")

        tabBarPlugin.setItems([homeMetadataJson], respond: respond.callback)
        guard let items = tabBar.items else {
            XCTFail("Expected the tabbar to have items, but there are no items (tabBar.items returned nil) in the tabbar")
            return
        }
        XCTAssertEqual(items.count, 1)
        XCTAssertEqual(tabBar.selectedItem!.title!, "Home")

        let metadataJsons = [
            createTabBarItemMetadataJson(id: "favourites", title: "Favourites"),
            homeMetadataJson,
            createTabBarItemMetadataJson(id: "cart", title: "Cart")
        ]

        tabBarPlugin.setItems(metadataJsons, respond: respond.callback)

        guard let otherItems = tabBar.items else {
            XCTFail("Expected the tabbar to have items, but there are no items (tabBar.items returned nil) in the tabbar")
            return
        }
        XCTAssertEqual(otherItems.count, 3)
        XCTAssertEqual(tabBar.selectedItem!.title!, "Home")
    }

    func testSetItemsWithEmptyList() {
        let metadataJsons = [
            createTabBarItemMetadataJson(id: "home", title: "Home")
        ]

        tabBarPlugin.setItems(metadataJsons, respond: respond.callback)
        guard let items = tabBar.items else {
            XCTFail("Expected the tabbar to have items, but there are no items (tabBar.items returned nil) in the tabbar")
            return
        }
        XCTAssertEqual(items.count, 1)

        tabBarPlugin.setItems([], respond: respond.callback)

        guard let otherItems = tabBar.items else {
            XCTFail("Expected the tabbar to have items, but there are no items (tabBar.items returned nil) in the tabbar")
            return
        }
        XCTAssertEqual(otherItems.count, 0)
    }
}

// Helper function inserted by Swift 4.2 migrator.
fileprivate func convertFromOptionalNSAttributedStringKeyDictionary(_ input: [NSAttributedString.Key: Any]?) -> [String: Any]? {
	guard let input = input else { return nil }
	return Dictionary(uniqueKeysWithValues: input.map {key, value in (key.rawValue, value)})
}
