//
//  NavigationController.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 10/24/19.
//  Copyright © 2019 Verizon Wireless. All rights reserved.
//

import UIKit

@objcMembers open class NavigationController: UINavigationController, MVMCoreViewManagerViewControllerProtocol {
    public weak var manager: (UIViewController & MVMCoreViewManagerProtocol)?

    /// Getter for the main navigation controller
    public static func navigationController() -> Self? {
        return MVMCoreActionUtility.initializerClassCheck(MVMCoreUISession.sharedGlobal()?.navigationController, classToVerify: self) as? Self
    }
    
    /// Sets up the application with a navigation controller
    public static func setupNavigationController() -> Self? {
        let navigationController = self.init()
        MVMCoreUISession.sharedGlobal()?.navigationController = navigationController
        MVMCoreNavigationHandler.shared()?.viewControllerToPresentOn = navigationController
        MVMCoreNavigationHandler.shared()?.navigationController = navigationController
        MVMCoreNavigationHandler.shared()?.addDelegate(navigationController)
        navigationController.setNavigationBarUI(with: NavigationItemModel())
        return navigationController
    }
    
    /// Sets up the application with a navigation controller as the main container.
    public static func setupNavigationControllerAsMainController() -> Self? {
        guard let navigationController = setupNavigationController() else { return nil }
        MVMCoreUISession.sharedGlobal()?.setup(asStandardLoadViewDelegate: navigationController)
        return navigationController
    }
    
    /// Convenience function to return the navigation model of the lowest controller traversing managers if applicable.
    public func getNavigationModel(from viewController: UIViewController) -> NavigationItemModelProtocol? {
        return (viewController as? PageProtocol)?.pageModel?.navigationBar
    }
    
    /// Verifies the controller is the currently displayed controller.
    public func isDisplayed(viewController: UIViewController) -> Bool {
        guard let topViewController = topViewController,
              viewController == MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController) else {
            return false
        }
        return true
    }
}

extension NavigationController: MVMCoreViewManagerProtocol {
    public func getCurrentViewController() -> UIViewController? {
        guard let topViewController = topViewController else { return nil }
        return MVMCoreUIUtility.getViewControllerTraversingManagers(topViewController)
    }
    
    public func containsPage(withPageType pageType: String?) -> Bool {
        for controller in viewControllers {
            if let manager = controller as? MVMCoreViewManagerProtocol,
               manager.containsPage(withPageType: pageType) {
                return true
            } else if let controller = controller as? MVMCoreViewControllerProtocol,
                      controller.pageType == pageType {
                return true
            }
        }
        return false
    }
    
    public func newDataReceived(in viewController: UIViewController) {
        if isDisplayed(viewController: viewController),
           let topViewController = topViewController,
           let model = getNavigationModel(from: viewController) {
            setNavigationItem(with: model, for: topViewController)
            setNavigationBarUI(with: model)
            
            navigationBar.setNeedsLayout()
            navigationBar.layoutIfNeeded()
        }
        manager?.newDataReceived?(in: viewController)
    }
    
    public func willDisplay(_ viewController: UIViewController) {
        if let topViewController = topViewController,
           isDisplayed(viewController: viewController),
           let model = getNavigationModel(from: viewController) {
            setNavigationItem(with: model, for: topViewController)
            setNavigationBarUI(with: model)
            
            navigationBar.setNeedsLayout()
            navigationBar.layoutIfNeeded()
        }
        manager?.willDisplay?(viewController)
    }
    
    public func displayedViewController(_ viewController: UIViewController) {
        manager?.displayedViewController?(viewController)
    }
}

extension NavigationController: MVMCorePresentationDelegateProtocol {
    public func navigationController(_ navigationController: UINavigationController, prepareDisplayFor viewController: UIViewController) {
        if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
            MVMCoreViewManagerViewControllerProtocolHelper.helpSetManager(self, viewController: controller)
        }
        guard self == navigationController,
              let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController),
              let model = getNavigationModel(from: newViewController) else { return }
        setNavigationItem(with: model, for: viewController)
        setNavigationBarUI(with: model)
    }
    
    public func navigationController(_ navigationController: UINavigationController, willDisplay viewController: UIViewController) {
        guard self == navigationController,
              let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
        manager?.willDisplay?(newViewController)
    }
    
    public func navigationController(_ navigationController: UINavigationController, displayedViewController viewController: UIViewController) {
        guard self == navigationController,
              let newViewController = MVMCoreUIUtility.getViewControllerTraversingManagers(viewController) else { return }
        manager?.displayedViewController?(newViewController)
        if let controller = viewController as? (UIViewController & MVMCoreViewManagerViewControllerProtocol) {
            controller.viewControllerReady?(inManager: self)
        }
    }
}

extension UIColor {
    func image(_ size: CGSize = CGSize(width: 1, height: 1)) -> UIImage {
        return UIGraphicsImageRenderer(size: size).image { rendererContext in
            self.setFill()
            rendererContext.fill(CGRect(origin: .zero, size: size))
        }
    }
}
