//
//  ContainerHelper.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 1/21/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//
//  A Helper that consolidates some common container logic

import Foundation


open class ContainerHelper: NSObject {
    //--------------------------------------------------
    // MARK: - Constraints
    //--------------------------------------------------
    
    open var leftConstraint: NSLayoutConstraint?
    open var topConstraint: NSLayoutConstraint?
    open var bottomConstraint: NSLayoutConstraint?
    open var rightConstraint: NSLayoutConstraint?
    
    open var alignCenterHorizontalConstraint: NSLayoutConstraint?
    open var alignCenterLeftConstraint: NSLayoutConstraint?
    open var alignCenterRightConstraint: NSLayoutConstraint?
    
    open var alignCenterVerticalConstraint: NSLayoutConstraint?
    open var alignCenterTopConstraint: NSLayoutConstraint?
    open var alignCenterBottomConstraint: NSLayoutConstraint?

    open var leftLowConstraint: NSLayoutConstraint?
    open var topLowConstraint: NSLayoutConstraint?
    open var bottomLowConstraint: NSLayoutConstraint?
    open var rightLowConstraint: NSLayoutConstraint?
    
    //--------------------------------------------------
    // MARK: - Methods
    //--------------------------------------------------
    
    open func constrainView(_ view: UIView) {
        guard let margins = view.superview?.layoutMarginsGuide else { return }
        
        leftConstraint?.isActive = false
        leftConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor)
        leftConstraint?.isActive = true
        
        topConstraint?.isActive = false
        topConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor)
        topConstraint?.isActive = true
        
        rightConstraint?.isActive = false
        rightConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor)
        rightConstraint?.isActive = true
        
        bottomConstraint?.isActive = false
        bottomConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        bottomConstraint?.isActive = true
        
        alignCenterHorizontalConstraint = view.centerXAnchor.constraint(equalTo: margins.centerXAnchor)
        alignCenterLeftConstraint = view.leftAnchor.constraint(greaterThanOrEqualTo: margins.leftAnchor)
        alignCenterRightConstraint = margins.rightAnchor.constraint(greaterThanOrEqualTo: view.rightAnchor)

        alignCenterVerticalConstraint = view.centerYAnchor.constraint(equalTo: margins.centerYAnchor)
        alignCenterTopConstraint = view.topAnchor.constraint(greaterThanOrEqualTo: margins.topAnchor)
        alignCenterBottomConstraint = margins.bottomAnchor.constraint(greaterThanOrEqualTo: view.bottomAnchor)
        
        leftLowConstraint?.isActive = false
        leftLowConstraint = view.leftAnchor.constraint(equalTo: margins.leftAnchor)
        leftLowConstraint?.priority = UILayoutPriority(rawValue: 200)
        leftLowConstraint?.isActive = true
        
        topLowConstraint?.isActive = false
        topLowConstraint = view.topAnchor.constraint(equalTo: margins.topAnchor)
        topLowConstraint?.priority = UILayoutPriority(rawValue: 200)
        topLowConstraint?.isActive = true
        
        rightLowConstraint?.isActive = false
        rightLowConstraint = margins.rightAnchor.constraint(equalTo: view.rightAnchor)
        rightLowConstraint?.priority = UILayoutPriority(rawValue: 200)
        rightLowConstraint?.isActive = true
        
        bottomLowConstraint?.isActive = false
        bottomLowConstraint = margins.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        bottomLowConstraint?.priority = UILayoutPriority(rawValue: 200)
        bottomLowConstraint?.isActive = true
    }
    
    open func setAccessibility(_ view: UIView) {
        guard let superView = view.superview else { return }
        superView.isAccessibilityElement = false
        if let elements = view.accessibilityElements {
            superView.accessibilityElements = elements
        } else {
            superView.accessibilityElements = [view]
        }
    }
    
    open func alignHorizontal(_ alignment: UIStackView.Alignment) {
        switch alignment {
        case .center:
            alignCenterHorizontalConstraint?.isActive = true
            alignCenterLeftConstraint?.isActive = true
            alignCenterRightConstraint?.isActive = true
            leftConstraint?.isActive = false
            rightConstraint?.isActive = false
        case .leading:
            alignCenterHorizontalConstraint?.isActive = false
            alignCenterLeftConstraint?.isActive = false
            alignCenterRightConstraint?.isActive = true
            leftConstraint?.isActive = true
            rightConstraint?.isActive = false
        case .trailing:
            alignCenterHorizontalConstraint?.isActive = false
            alignCenterLeftConstraint?.isActive = true
            alignCenterRightConstraint?.isActive = false
            leftConstraint?.isActive = false
            rightConstraint?.isActive = true
        case .fill:
            alignCenterHorizontalConstraint?.isActive = false
            alignCenterLeftConstraint?.isActive = false
            alignCenterRightConstraint?.isActive = false
            leftConstraint?.isActive = true
            rightConstraint?.isActive = true
        default: break
        }
    }
 
    open func alignVertical(_ alignment: UIStackView.Alignment) {
        switch alignment {
        case .center:
            alignCenterVerticalConstraint?.isActive = true
            alignCenterTopConstraint?.isActive = true
            alignCenterBottomConstraint?.isActive = true
            topConstraint?.isActive = false
            bottomConstraint?.isActive = false
        case .leading:
            alignCenterVerticalConstraint?.isActive = false
            alignCenterTopConstraint?.isActive = false
            alignCenterBottomConstraint?.isActive = true
            topConstraint?.isActive = true
            bottomConstraint?.isActive = false
        case .trailing:
            alignCenterVerticalConstraint?.isActive = false
            alignCenterTopConstraint?.isActive = true
            alignCenterBottomConstraint?.isActive = false
            topConstraint?.isActive = false
            bottomConstraint?.isActive = true
        case .fill:
            alignCenterVerticalConstraint?.isActive = false
            alignCenterTopConstraint?.isActive = false
            alignCenterBottomConstraint?.isActive = false
            topConstraint?.isActive = true
            bottomConstraint?.isActive = true
        default: break
        }
    }
    
    public static func getAlignment(for string: String) -> UIStackView.Alignment? {
        switch string {
        case "leading":
            return .leading
        case "trailing":
            return .trailing
        case "center":
            return .center
        case "fill":
            return .fill
        default:
            return nil
        }
    }
    
    public static func getAlignmentString(for alignment: UIStackView.Alignment?) -> String? {
        switch alignment {
        case .leading:
            return "leading"
        case .trailing:
            return "trailing"
        case .center:
            return "center"
        case .fill:
            return "fill"
        default:
            return nil
        }
    }
    
    /// Updates the view margins according to model and size. If useHorizontalMargins is true, we will try to use the left and right padding, else we will default to the normal gutters. If useVerticalMargins is true, we will try to use the top and bottom padding. All else, we use zero.
    open func updateViewMargins(_ view: UIView, model: ContainerModelProtocol?, size: CGFloat) {
        let left = (model?.useHorizontalMargins ?? false) ? (model?.leftPadding ?? Padding.Component.horizontalPaddingForSize(size)) : 0.0
        let right = (model?.useHorizontalMargins ?? false) ? (model?.rightPadding ?? Padding.Component.horizontalPaddingForSize(size)) : 0.0
        let top = (model?.useVerticalMargins ?? false) ? (model?.topPadding ?? 0.0) : 0.0
        let bottom = (model?.useVerticalMargins ?? false) ? (model?.bottomPadding ?? 0.0) : 0.0
        MVMCoreDispatchUtility.performBlock(onMainThread: {
            MVMCoreUIUtility.setMarginsFor(view, leading: left, top: top, trailing: right, bottom: bottom)
        })
    }
    
    open func set(with model: ContainerModelProtocol, for contained: MVMCoreUIViewConstrainingProtocol?) {
        if let horizontalAlignment = model.horizontalAlignment ?? contained?.horizontalAlignment?() {
            alignHorizontal(horizontalAlignment)
        }
        if let verticalAlignment = model.verticalAlignment ?? contained?.verticalAlignment?() {
            alignVertical(verticalAlignment)
        }
    }
    
    open func set(with JSON: [AnyHashable: Any]?, for contained: UIView) {
        if let horizontalAlignmentString = JSON?.optionalStringForKey("horizontalAlignment"), let alignment = ContainerHelper.getAlignment(for: horizontalAlignmentString) ?? (contained as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() {
            alignHorizontal(alignment)
        } else if let alignment = (contained as? MVMCoreUIViewConstrainingProtocol)?.horizontalAlignment?() {
            alignHorizontal(alignment)
        }
        
        if let verticalAlignmentString = JSON?.optionalStringForKey("verticalAlignment"), let alignment = ContainerHelper.getAlignment(for: verticalAlignmentString) ?? (contained as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() {
            alignVertical(alignment)
        } else if let alignment = (contained as? MVMCoreUIViewConstrainingProtocol)?.verticalAlignment?() {
            alignVertical(alignment)
        }
    }
}
