//
//  CollapsableNotification.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 9/18/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import Foundation

@objcMembers open class CollapsableNotification: View {
    //--------------------------------------------------
    // MARK: - Outlets
    //--------------------------------------------------

    public let topView = CollapsableNotificationTopView()
    public let bottomView = NotificationView()
    public var verticalStack: UIStackView!

    //--------------------------------------------------
    // MARK: - Life Cycle
    //--------------------------------------------------

    public override func setupView() {
        super.setupView()

        verticalStack = UIStackView(arrangedSubviews: [topView, bottomView])
        verticalStack.translatesAutoresizingMaskIntoConstraints = false
        verticalStack.axis = .vertical
        verticalStack.alignment = .fill
        verticalStack.distribution = .fill
        addSubview(verticalStack)
        NSLayoutConstraint.constraintPinSubview(verticalStack, pinTop: true, topConstant: 0, pinBottom: true, bottomConstant: 0, pinLeft: true, leftConstant: 0, pinRight: true, rightConstant: 0)
        
        reset()
    }
    
    open override func updateView(_ size: CGFloat) {
        super.updateView(size)
        verticalStack.updateView(size)
    }
    
    open override func reset() {
        super.reset()
        verticalStack.reset()
        backgroundColor = .mvmGreen()
    }
    
    //--------------------------------------------------
    // MARK: - Molecule
    //--------------------------------------------------
    
    open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        guard let model = model as? CollapsableNotificationModel else { return }
        topView.set(with: model, delegateObject, additionalData)
        bottomView.set(with: model, delegateObject, additionalData)
        
        // Update top view default noop to expand.
        if let topAction = model.topAction,
            topAction.actionType == ActionNoopModel.identifier {
            topView.button.addActionBlock(event: .touchUpInside) { [weak self] (button) in
                Button.performButtonAction(with: topAction, button: button, delegateObject: delegateObject, additionalData: additionalData)
                self?.expand(topViewShowing: model.alwaysShowTopLabel)
            }
        }

        // Set initial collapse/expand state.
        topView.isHidden = !model.alwaysShowTopLabel && !model.initiallyCollapsed
        topView.button.isUserInteractionEnabled = model.initiallyCollapsed
        bottomView.isHidden = model.initiallyCollapsed
        verticalStack.layoutIfNeeded()
        
        if !model.initiallyCollapsed {
            autoCollapse()
        }
    }
    
    open func performBlockOperation(with block: @escaping (MVMCoreBlockOperation) -> Void) {
        let operation = MVMCoreBlockOperation(block: block)!
        MVMCoreNavigationHandler.shared()?.addNavigationOperation(operation)
    }
    
    /// Collapses after a delay
    open func autoCollapse() {
        let delay: DispatchTimeInterval = DispatchTimeInterval.seconds((model as? CollapsableNotificationModel)?.collapseTime ?? 5)
        DispatchQueue.main.asyncAfter(deadline: .now() + delay) { [weak self] in
            // If accessibility focused, delay collapse.
            guard let self = self else { return }
            if MVMCoreUIUtility.viewContainsAccessiblityFocus(self) {
                NotificationCenter.default.addObserver(self, selector: #selector(self.accessibilityFocusChanged(notification:)), name: UIAccessibility.elementFocusedNotification, object: nil)
            } else {
                self.collapse()
            }
        }
    }
    
    /// Collapses to show just the top view.
    open func collapse(animated: Bool = true) {
        guard !bottomView.isHidden else { return }
        performBlockOperation { [weak self] (operation) in
            let strongSelf = self
            MVMCoreDispatchUtility.performBlock(onMainThread: {
                MVMCoreUITopAlertView.sharedGlobal()?.superview?.layoutIfNeeded()
                let animation = {
                    strongSelf?.topView.isHidden = false
                    strongSelf?.bottomView.isHidden = true
                    strongSelf?.verticalStack.layoutIfNeeded()
                }
                let completion: (Bool) -> Void = { (finished) in
                    strongSelf?.topView.button.isUserInteractionEnabled = true
                    MVMCoreUITopAlertView.sharedGlobal()?.superview?.layoutIfNeeded()
                    UIAccessibility.post(notification: .layoutChanged, argument: strongSelf?.getAccessibilityLayoutChangedArgument())
                    operation.markAsFinished()
                }
                
                if animated {
                    UIView.animate(withDuration: 0.5, animations: animation, completion: completion)
                } else {
                    animation()
                    completion(true)
                }
            })
        }
    }
    
    /// Expands to show the bottom view.
    open func expand(topViewShowing: Bool = false, animated: Bool = true) {
        guard bottomView.isHidden else { return }
        performBlockOperation { [weak self] (operation) in
            let strongSelf = self
            MVMCoreDispatchUtility.performBlock(onMainThread: {
                MVMCoreUITopAlertView.sharedGlobal()?.superview?.layoutIfNeeded()
                strongSelf?.topView.button.isUserInteractionEnabled = false
                let animation = {
                    strongSelf?.topView.isHidden = !topViewShowing
                    strongSelf?.bottomView.isHidden = false
                    strongSelf?.verticalStack.layoutIfNeeded()
                }
                let completion: (Bool) -> Void = { (finished) in
                    MVMCoreUITopAlertView.sharedGlobal()?.superview?.layoutIfNeeded()
                    UIAccessibility.post(notification: .layoutChanged, argument: strongSelf?.getAccessibilityLayoutChangedArgument())
                    strongSelf?.autoCollapse()
                    operation.markAsFinished()
                }
                
                if animated {
                    UIView.animate(withDuration: 0.5, animations: animation, completion: completion)
                } else {
                    animation()
                    completion(true)
                }
            })
        }
    }
    
    open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?) -> CGFloat? {
        return 120
    }
   
    /// Collapse if focus is no longer on this top alert.
    @objc func accessibilityFocusChanged(notification: Notification) {
        if (notification.userInfo?[UIAccessibility.focusedElementUserInfoKey] != nil) && !MVMCoreUIUtility.viewContainsAccessiblityFocus(self) {
            NotificationCenter.default.removeObserver(self, name: UIAccessibility.elementFocusedNotification, object: nil)
            collapse()
        }
    }
}

extension CollapsableNotification: StatusBarUI {
    func getStatusBarUI() -> (color: UIColor, style: UIStatusBarStyle) {
        let color = backgroundColor ?? UIColor.mvmGreen
        var greyScale: CGFloat = 0
        topView.label.textColor.getWhite(&greyScale, alpha: nil)
        return (color, greyScale > 0.5 ? .lightContent : .default)
    }
}

extension CollapsableNotification: AccessibilityProtocol {
    public func getAccessibilityLayoutChangedArgument() -> Any? {
        if !topView.isHidden {
            return topView
        } else {
            return bottomView.headline
        }
    }
}
