//
//  PageBehaviorHandlerProtocol.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 3/29/21.
//  Copyright © 2021 Verizon Wireless. All rights reserved.
//


public protocol PageBehaviorHandlerProtocol {
    var behaviors: [PageBehaviorProtocol]? { get set }
}

public extension PageBehaviorHandlerProtocol {
    
    /// Creates the behaviors and sets the variable.
    func createBehaviors(for behaviorModels: [PageBehaviorModelProtocol], delegateObject: MVMCoreUIDelegateObject?) -> [PageBehaviorProtocol] {
        var behaviors = [PageBehaviorProtocol]()
        for behaviorModel in behaviorModels {
            do {
                let handlerType = try ModelRegistry.getHandler(behaviorModel) as! PageBehaviorProtocol.Type
                let behavior = handlerType.init(model: behaviorModel, delegateObject: delegateObject)
                behaviors.append(behavior)
            } catch {
                if let errorObject = MVMCoreErrorObject.createErrorObject(for: error, location: #function) {
                    MVMCoreLoggingHandler.shared()?.addError(toLog: errorObject)
                }
            }
        }
        return behaviors
    }
    
    mutating func applyBehaviors(pageBehaviorModel: PageBehaviorContainerModelProtocol, delegateObject: MVMCoreUIDelegateObject?) {
        // Pull the existing behaviors.
        var behaviors = (behaviors ?? []).filter { $0.transcendsPageUpdates }
        // Create and append any new behaviors based on the incoming models.
        let newBehaviors = createBehaviors(for: pageBehaviorModel.behaviors ?? [], delegateObject: delegateObject)
        behaviors.append(contentsOf: newBehaviors)
        
        // Apply them to the page.
        self.behaviors = behaviors.count > 0 ? behaviors : nil
        
        // Ask the session to apply any more. (Curently inverted contol due to Swift <--> Obj-C conflict.
        if let viewController = self as? UIViewController {
            MVMCoreUISession.sharedGlobal()?.applyGlobalBehaviors(to: viewController)
        }
    }
    
    /// Executes all behaviors of type.
    func executeBehaviors<T>(_ behaviorBlock: (_ behavior: T) -> Void) {
        behaviors?.compactMap { $0 as? T }.forEach { behaviorBlock($0) }
    }
    
    func executeThrowingBehaviors<T>(_ behaviourBlock: (_ behavior: T) throws -> Bool) throws -> Bool {
        return try behaviors?.compactMap({$0 as? T}).allSatisfy({ return try behaviourBlock($0) }) ?? true
    }
}

public extension PageBehaviorHandlerProtocol where Self: MVMCoreViewControllerProtocol {
    
    mutating func applyBehaviors(pageBehaviorModel: PageBehaviorContainerModelProtocol) {
        applyBehaviors(pageBehaviorModel: pageBehaviorModel, delegateObject: delegateObject?() as? MVMCoreUIDelegateObject)
    }
    
}
