//
//  PillButton.swift
//  MVMCoreUI
//
//  Created by Scott Pfeil on 1/28/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import UIKit


open class PillButton: Button, MVMCoreUIViewConstrainingProtocol {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    /// Used to size the button.
    var size = MVMCoreUIUtility.getWidth()
    
    var buttonModel: ButtonModel? {
        get { model as? ButtonModel }
    }
    
    /// Need to re-style on set.
    open override var isEnabled: Bool {
        didSet { style() }
    }
    
    open var buttonSize: Styler.Button.Size = .standard {
        didSet { buttonModel?.size = buttonSize }
    }
    
    //--------------------------------------------------
    // MARK: - Initializers
    //--------------------------------------------------
    
    @objc public convenience init(asPrimaryButton isPrimary: Bool, makeTiny istiny: Bool) {
        self.init()
        buttonSize = istiny ? .tiny : .standard
        isPrimary ? stylePrimary() : styleSecondary()
    }
    
    //--------------------------------------------------
    // MARK: - Computed Properties
    //--------------------------------------------------
    
    public var enabledTitleColor: UIColor? {
        get { titleColor(for: .normal) }
        set { setTitleColor(newValue, for: .normal) }
    }
    
    public var disabledTitleColor: UIColor? {
        get { titleColor(for: .disabled) }
        set { setTitleColor(newValue, for: .disabled) }
    }
    
    public var borderColor: UIColor? {
        get {
            guard let currentColor = layer.borderColor else { return nil }
            return UIColor(cgColor: currentColor)
        }
        set { layer.borderColor = newValue?.cgColor }
    }
    
    //--------------------------------------------------
    // MARK: - Methods
    //--------------------------------------------------
    
    /// The primary styling for a button. Should be used for main buttons
    public func stylePrimary() {
        
        enabledTitleColor = buttonModel?.enabledColors.text ?? .mvmWhite
        disabledTitleColor = buttonModel?.disabledColors.text ?? .mvmWhite
        layer.borderWidth = 0
        backgroundColor = isEnabled ? buttonModel?.enabledColors.fill ?? .mvmBlack : buttonModel?.disabledColors.fill ?? .mvmCoolGray6
    }
    
    /// The secondary styling for a button. Should be used for secondary buttons
    public func styleSecondary() {
        
        enabledTitleColor = buttonModel?.enabledColors.text ?? .mvmBlack
        disabledTitleColor = buttonModel?.disabledColors.text ?? .mvmCoolGray6
        backgroundColor = .clear
        layer.borderWidth = 1
        borderColor = isEnabled ? buttonModel?.enabledColors.border ?? .mvmBlack : buttonModel?.disabledColors.border ?? .mvmCoolGray6
    }
    
    /// Styles the button based on the model style
    private func style() {
        
        switch buttonModel?.style {
        case .secondary:
            styleSecondary()
            
        default:
            stylePrimary()
        }
        
        if let titleColor = buttonModel?.enabledColors.text {
            enabledTitleColor = titleColor
        }
        
        if let disabledTitleColor = buttonModel?.disabledColors.text {
            self.disabledTitleColor = disabledTitleColor
        }
        
        #if DEBUG
        // Useful to detect with isHittable when performing UI testing.
        isAccessibilityElement = isEnabled
        #endif
        
        if isEnabled {
            if let fillColor = buttonModel?.enabledColors.fill {
                backgroundColor = fillColor
            }
            
            if let borderColor = buttonModel?.enabledColors.border {
                layer.borderWidth = 1
                self.borderColor = borderColor
            }
        } else {
            if let fillColor = buttonModel?.disabledColors.fill {
                backgroundColor = fillColor
            }
            
            if let borderColor = buttonModel?.disabledColors.border {
                layer.borderWidth = 1
                self.borderColor = borderColor
            }
        }
    }
    
    private func getInnerPadding() -> CGFloat {
        getHeight() / 2.0
    }
    
    private func getHeight() -> CGFloat {
        PillButton.getHeight(for: buttonSize, size: size)
    }
    
    public static func getHeight(for buttonSize: Styler.Button.Size?, size: CGFloat) -> CGFloat {
        
        switch buttonSize {
        case .tiny:
            let tinyHeight = Styler.Button.Size.tiny.getHeight()
            return MFSizeObject(standardSize: tinyHeight,
                                standardiPadPortraitSize: 34,
                                iPadProLandscapeSize: 38)?.getValueBased(onSize: size) ?? tinyHeight
            
        default:
            let standardHeight = Styler.Button.Size.standard.getHeight()
            return MFSizeObject(standardSize: standardHeight,
                                standardiPadPortraitSize: 46,
                                iPadProLandscapeSize: 50)?.getValueBased(onSize: size) ?? standardHeight
        }
    }
    
    private func getMinimumWidth() -> CGFloat {
        
        switch buttonSize {
        case .tiny:
            return MFSizeObject(standardSize: 49,
                                standardiPadPortraitSize: 90,
                                iPadProLandscapeSize: 135)?.getValueBased(onSize: size) ?? 49
            
        default: return 151
        }
    }
    
    open override var intrinsicContentSize: CGSize {
        if buttonSize == .tiny {
            let size = super.intrinsicContentSize
            let width = size.width + (2 * getInnerPadding())
            return CGSize(width: max(width, getMinimumWidth()), height: getHeight())
        } else {
            let width = Padding.Component.gutterForApplicationWidth + (2.0 * Padding.Component.columnFor(size: MVMCoreUISplitViewController.getApplicationViewWidth()))
            return CGSize(width: min(292, width), height: getHeight())
        }
    }
    
    //--------------------------------------------------
    // MARK: - MVMCoreViewProtocol
    //--------------------------------------------------
    
    open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        // The button will get styled in the enable check in super.
        super.set(with: model, delegateObject, additionalData)
        
        guard let model = model as? ButtonModel else { return }
        setTitle(model.title, for: .normal)
        if let accessibilityText = model.accessibilityText {
            accessibilityLabel = accessibilityText
        }
        
        if let size = model.size {
            buttonSize = size
        }
        
        model.updateUI = { [weak self] in
            MVMCoreDispatchUtility.performBlock(onMainThread: {
                self?.enableField(model.enabled)
            })
        }
        
        FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
    }
    
    open override class func estimatedHeight(with model: MoleculeModelProtocol, _ delegateObject:  MVMCoreUIDelegateObject?) -> CGFloat? {
        PillButton.getHeight(for: (model as? ButtonModel)?.size, size: MVMCoreUIUtility.getWidth())
    }
    
    open override func updateView(_ size: CGFloat) {
        super.updateView(size)
        self.size = size
        
        invalidateIntrinsicContentSize()
        
        switch buttonSize {
        case .tiny:
            titleLabel?.font = MFFonts.mfFont75Bd(11 * (intrinsicContentSize.height / Styler.Button.Size.tiny.getHeight()))
            
        default:
            titleLabel?.font = MFFonts.mfFont75Bd(13 * (intrinsicContentSize.height / Styler.Button.Size.standard.getHeight()))
        }
        
        layer.cornerRadius = getInnerPadding()
    }
    
    open override func setupView() {
        super.setupView()
        
        titleLabel?.numberOfLines = 1
        titleLabel?.lineBreakMode = .byTruncatingTail
        titleLabel?.textAlignment = .center
        contentHorizontalAlignment = .center
        stylePrimary()
    }
    
    //--------------------------------------------------
    // MARK: - MVMCoreUIViewConstrainingProtocol
    //--------------------------------------------------
    
    open func horizontalAlignment() -> UIStackView.Alignment { .center }
    
    public func enableField(_ enable: Bool) {
        isEnabled = enable
    }
}
