//
//  MVMCoreUISplitViewController+Extension.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 6/18/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import Foundation
import UIKit

// Navigation bar update functions
public extension MVMCoreUISplitViewController {
    
    /// Updates the state for various controls (navigation, tab, progress) for the controller.
    func updateState(with viewController: UIViewController) {
        guard let navigationController = navigationController,
              navigationController.isDisplayed(viewController: viewController) else { return }
        updateNavigationBarFor(viewController: viewController)
        updateProgressBar(for: viewController)
        updateTabBar(for: viewController)
    }
    
    // MARK: - Progress Bar
    /// Updates the progress bar based on the page json for the view controller.
    func updateProgressBar(for viewController: UIViewController) {
        guard let viewController = viewController as? MVMCoreViewControllerProtocol else { return }
        var progress: Float = 0.0
        if let progressString = viewController.loadObject??.pageJSON?.optionalStringForKey(KeyProgressPercent),
            let floatValue = Float(progressString) {
            progress = floatValue/100
        }
        setBottomProgressBarProgress(progress)
    }
    
    // MARK: - Tab Bar
    /// Updates the tab bar based on the page json for the view controller.
    func updateTabBar(for viewController: UIViewController) {
        let mvmViewController = viewController as? MVMCoreViewControllerProtocol
        tabBar?.delegateObject = mvmViewController?.delegateObject?() as? MVMCoreUIDelegateObject
        
        let navigationIndex = (MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 1) - 1
        
        // Set the highlighted index. In terms of priority, Page > Action > Previous.
        if let index = ((viewController as? PageProtocol)?.pageModel as? TabPageModelProtocol)?.tabBarIndex {
            tabBar?.highlightTab(at: index)
        } else if let index = mvmViewController?.loadObject??.requestParameters?.actionMap?["tabBarIndex"] as? Int {
            tabBar?.highlightTab(at: index)
        } else if navigationIndex < tabBarIndices.count,
                  let index = (tabBarIndices[navigationIndex] as? NSNumber)?.intValue {
            tabBar?.highlightTab(at: index)
        }
        
        // Store current tab index, so we can switch back when going back in hierarchy.
        if tabBarIndices.count > navigationIndex {
            tabBarIndices.removeObjects(in: NSRange(location: navigationIndex, length: tabBarIndices.count - navigationIndex))
        }
        if let currentIndex = tabBar?.currentTabIndex() {
            tabBarIndices.add(NSNumber(integerLiteral: currentIndex))
        } else {
            tabBarIndices.add(NSNull())
        }

        // Show/Hide. In terms of priority, Page > Action > Always Show.
        if let hidden = ((viewController as? PageProtocol)?.pageModel as? TabPageModelProtocol)?.tabBarHidden {
            updateTabBarShowing(!hidden)
        } else if let hidden = mvmViewController?.loadObject??.requestParameters?.actionMap?["tabBarHidden"] as? Bool {
            updateTabBarShowing(!hidden)
        } else {
            updateTabBarShowing(true)
        }
    }
    
    // MARK: - Navigation Bar
    /// Convenience function. Sets the navigation and split view properties for the view controller. Panel access is determined if view controller is a detail view protocol.
    func setNavigationBar(for viewController: UIViewController, navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol) {
        guard navigationController == self.navigationController,
            viewController == getCurrentDetailViewController() else {
            /// Not the split view navigation controller, skip split functions.
            return
        }

        setLeftPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isLeftPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
        setRightPanelIsAccessible((viewController as? MVMCoreUIDetailViewProtocol)?.isRightPanelAccessible?() ?? false, for: viewController, updateNavigationButtons: false)
        
        setLeftNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
        setRightNavigationButtons(navigationController: navigationController, navigationItemModel: navigationItemModel, viewController: viewController)
        
        setNavigationIconColor(navigationItemModel.tintColor.uiColor)
    }
    
    /// Sets the left navigation items for the view controller based on model and splitview.
    func setLeftNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
        guard let topViewController = navigationController.topViewController else { return }

        var leftItems: [UIBarButtonItem] = []
        let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject

        // Add back button first.
        if navigationItemModel?.hidesSystemBackButton == true {
            var showBackButton: Bool
            if let forceBackButton = navigationItemModel?.alwaysShowBackButton {
                showBackButton = forceBackButton
            } else {
                showBackButton = MVMCoreNavigationHandler.shared()?.getViewControllers(for: navigationController)?.count ?? 0 > 1
            }
            if showBackButton {
                if let backButtonModel = navigationItemModel?.backButton {
                    leftItems.append(backButtonModel.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
                } else if let backButton = backButton {
                    // Default to legacy if we have default back button.
                    leftItems.append(backButton)
                }
            }
        }
        
        // Add the panel button after the back button.
        if let panelButton = leftPanelButton,
            leftPanelIsAccessible,
            !leftPanelStaysExtended() {
            leftItems.append(panelButton)
        }
        
        // Add other model buttons
        if let leftItemModels = navigationItemModel?.additionalLeftButtons {
            for item in leftItemModels {
                leftItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
            }
        }
        
        // Add any buttons added by the splitview.
        if let additionalLeftButtons = additionalLeftButtons(for: viewController) {
            leftItems.append(contentsOf: additionalLeftButtons)
        }
        
        topViewController.navigationItem.setLeftBarButtonItems(leftItems.count > 0 ? leftItems : nil, animated: !DisableAnimations.boolValue)
    }
    
    /// Sets the right navigation items for the view controller based on model and splitview.
    func setRightNavigationButtons(navigationController: UINavigationController, navigationItemModel: NavigationItemModelProtocol?, viewController: UIViewController) {
        guard let topViewController = navigationController.topViewController else { return }

        let delegate = (viewController as? MVMCoreViewControllerProtocol)?.delegateObject?() as? MVMCoreUIDelegateObject
        var rightItems: [UIBarButtonItem] = []
        
        // Add the panel button first.
        if let panelButton = rightPanelButton,
            rightPanelIsAccessible,
            !rightPanelStaysExtended() {
            rightItems.append(panelButton)
        }
        
        // Add any buttons added by the splitview.
        if let additionalRightButtons = additionalRightButtons(for: viewController) {
            rightItems.append(contentsOf: additionalRightButtons)
        }
        
        // Add other model buttons
        if let rightItemModels = navigationItemModel?.additionalRightButtons {
            for item in rightItemModels {
                rightItems.append(item.createNavigationItemButton(delegateObject: delegate, additionalData: nil))
            }
        }
        
        topViewController.navigationItem.setRightBarButtonItems(rightItems.count > 0 ? rightItems : nil, animated: !DisableAnimations.boolValue)
    }
    
    @objc func navigationBarModelExists() -> Bool {
        // Legacy Navigation
        guard let currentViewController = getCurrentDetailViewController(),
              let _ = navigationController?.getNavigationModel(from: currentViewController) else { return false }
        return true
    }
    
    /// Convenience function to update the navigation bar if the controller is the current lowest controller.
    @objc func updateNavigationBarFor(viewController: UIViewController) {
        guard let navigationController = navigationController,
              navigationController.isDisplayed(viewController: viewController),
              let model = navigationController.getNavigationModel(from: viewController) else { return }
        setNavigationBar(for: viewController, navigationController: navigationController, navigationItemModel: model)
        guard !(topAlertView?.overridingStatusBar() ?? false) else { return }
        setStatusBarForCurrentViewController()
    }
    
    // MARK: - Status Bar
    /// Returns the bar style for the background color. Light if on a dark background, otherwise default.
    func getStatusBarStyle(for backgroundColor: UIColor?) -> UIStatusBarStyle {
        var greyScale: CGFloat = 0
        if backgroundColor?.getWhite(&greyScale, alpha: nil) == true,
              greyScale < 0.5 { return .lightContent }
        return .default
    }
    
    /// Updates the status bar background color and style.
    @objc func setStatusBarForCurrentViewController() {
        let viewController = getCurrentViewController() as? MVMCoreUIDetailViewProtocol
        let backgroundColor = viewController?.defaultStatusBarBackgroundColor?() ??
        navigationController?.navigationBar.standardAppearance.backgroundColor ??
        statusBarView?.backgroundColor

        let style = viewController?.defaultStatusBarStyle?() ??
        getStatusBarStyle(for: backgroundColor)

        setStatusBarBackgroundColor(backgroundColor, style: style)
    }
}

extension MVMCoreUISplitViewController: MVMCoreViewManagerProtocol {
    public func getCurrentViewController() -> UIViewController? {
        navigationController?.getCurrentViewController()
    }
    
    public func containsPage(withPageType pageType: String?) -> Bool {
        navigationController?.containsPage(withPageType: pageType) ?? false
    }
    
    public func willDisplay(_ viewController: UIViewController) {
        setupPanels()
        updateState(with: viewController)
    }
    
    public func newDataReceived(in viewController: UIViewController) {
        updateState(with: viewController)
    }
}
