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

import UIKit

public typealias FacadeElements = (fill: UIColor?, text: UIColor?, border: UIColor?)


open class ButtonModel: ButtonModelProtocol, MoleculeModelProtocol, FormGroupWatcherFieldProtocol {
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    //Making static property as class property so that subclasses can override getter function of the property
    open class var identifier: String { "button" }
    public var backgroundColor: Color?
    public var accessibilityIdentifier: String?
    public var accessibilityText: String?
    public var title: String
    public var action: ActionModelProtocol
    public var enabled: Bool = true
    public var style: Styler.Button.Style? {
        didSet {
            guard let style = style else { return }
            setFacade(by: style)
        }
    }
    public var size: Styler.Button.Size? = .standard
    public var groupName: String = ""
    public var inverted: Bool = false
    
    public lazy var enabledColors: FacadeElements = (fill: enabled_fillColor(),
                                                     text: enabled_textColor(),
                                                     border: enabled_borderColor())
    
    public lazy var disabledColors: FacadeElements = (fill: disabled_fillColor(),
                                                      text: disabled_textColor(),
                                                      border: disabled_borderColor())
    
    public var enabledFillColor: Color?
    public var enabledTextColor: Color?
    public var enabledBorderColor: Color?
    
    public var enabledFillColor_inverted: Color?
    public var enabledTextColor_inverted: Color?
    public var enabledBorderColor_inverted: Color?
    
    public var disabledFillColor: Color?
    public var disabledTextColor: Color?
    public var disabledBorderColor: Color?
    
    public var disabledFillColor_inverted: Color?
    public var disabledTextColor_inverted: Color?
    public var disabledBorderColor_inverted: Color?
    
    //--------------------------------------------------
    // MARK: - Methods
    //--------------------------------------------------
    /// Temporary binding mechanism for the view to update on enable changes.
    public var updateUI: ActionBlock?
    
    //--------------------------------------------------
    // MARK: - Initializers
    //--------------------------------------------------
    
    public init(with title: String, action: ActionModelProtocol) {
        self.title = title
        self.action = action
    }
    
    public init(secondaryButtonWith title: String, action: ActionModelProtocol) {
        self.title = title
        self.action = action
        style = .secondary
    }
    
    public init(primaryButtonWith title: String, action: ActionModelProtocol) {
        self.title = title
        self.action = action
        style = .primary
    }
    
    //--------------------------------------------------
    // MARK: - Methods
    //--------------------------------------------------
    
    public func enabled_fillColor() -> UIColor? {
        (inverted ? enabledFillColor_inverted : enabledFillColor)?.uiColor
    }
    
    public func enabled_textColor() -> UIColor? {
        (inverted ? enabledTextColor_inverted : enabledTextColor)?.uiColor
    }
    
    public func enabled_borderColor() -> UIColor? {
        (inverted ? enabledBorderColor_inverted : enabledBorderColor)?.uiColor
    }
    
    public func disabled_fillColor() -> UIColor? {
        (inverted ? disabledFillColor_inverted : disabledFillColor)?.uiColor
    }
    
    public func disabled_textColor() -> UIColor? {
        (inverted ? disabledTextColor_inverted : disabledTextColor)?.uiColor
    }
    
    public func disabled_borderColor() -> UIColor? {
        (inverted ? disabledBorderColor_inverted : disabledBorderColor)?.uiColor
    }
    
    /// Defines the default appearance for the primary style.
    func setPrimaryFacade() {
        
        if enabledFillColor == nil && enabledTextColor == nil {
            enabledFillColor = Color(uiColor: .mvmBlack)
            enabledTextColor = Color(uiColor: .mvmWhite)
        }
        
        if disabledFillColor == nil && disabledTextColor == nil {
            disabledFillColor = Color(uiColor: .mvmCoolGray6)
            disabledTextColor = Color(uiColor: .mvmWhite)
        }
        
        enabledFillColor_inverted = Color(uiColor: .mvmWhite)
        enabledTextColor_inverted = Color(uiColor: .mvmBlack)
        disabledFillColor_inverted = Color(uiColor: .mvmCoolGray6)
        disabledTextColor_inverted = Color(uiColor: .mvmBlack)
    }
    
    /// Defines the default appearance for the Secondary style.
    func setSecondaryFacade() {
        
        if enabledTextColor == nil && enabledBorderColor == nil {
            enabledTextColor = Color(uiColor: .mvmBlack)
            enabledBorderColor = Color(uiColor: .mvmBlack)
        }
        
        if disabledTextColor == nil && disabledBorderColor == nil {
            disabledTextColor = Color(uiColor: .mvmCoolGray6)
            disabledBorderColor = Color(uiColor: .mvmCoolGray6)
        }
        
        enabledTextColor_inverted = Color(uiColor: .mvmWhite)
        enabledBorderColor_inverted = Color(uiColor: .mvmWhite)
        disabledTextColor_inverted = Color(uiColor: .mvmCoolGray6)
        disabledBorderColor_inverted = Color(uiColor: .mvmCoolGray6)
    }
    
    public func setFacade(by style: Styler.Button.Style) {
        
        switch style {
        case .primary:
            setPrimaryFacade()
            
        case .secondary:
            setSecondaryFacade()
        }
    }
    
    //--------------------------------------------------
    // MARK: - Keys
    //--------------------------------------------------
    
    private enum CodingKeys: String, CodingKey {
        case moleculeName
        case backgroundColor
        case accessibilityIdentifier
        case accessibilityText
        case title
        case inverted
        case action
        case enabled
        case style
        case size
        case groupName
        case fillColor
        case textColor
        case borderColor
        case disabledFillColor
        case disabledTextColor
        case disabledBorderColor
    }
    
    //--------------------------------------------------
    // MARK: - Codec
    //--------------------------------------------------
    
    required public init(from decoder: Decoder) throws {
        let typeContainer = try decoder.container(keyedBy: CodingKeys.self)
        
        backgroundColor = try typeContainer.decodeIfPresent(Color.self, forKey: .backgroundColor)
        accessibilityIdentifier = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityIdentifier)
        accessibilityText = try typeContainer.decodeIfPresent(String.self, forKey: .accessibilityText)
        title = try typeContainer.decode(String.self, forKey: .title)
        action = try typeContainer.decodeModel(codingKey: .action)
        
        if let style = try typeContainer.decodeIfPresent(Styler.Button.Style.self, forKey: .style) {
            self.style = style
            setFacade(by: style)
        }
        
        if let size = try typeContainer.decodeIfPresent(Styler.Button.Size.self, forKey: .size) {
            self.size = size
        }
        
        if let enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) {
            self.enabled = enabled
        }
        
        if let inverted = try typeContainer.decodeIfPresent(Bool.self, forKey: .inverted) {
            self.inverted = inverted
        }
        
        if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
            self.groupName = groupName
        }
        
        if let enabledFillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .fillColor) {
            self.enabledFillColor = enabledFillColor
        }
        
        if let enabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .textColor) {
            self.enabledTextColor = enabledTextColor
        }
        
        if let enabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .borderColor) {
            self.enabledBorderColor = enabledBorderColor
        }
        
        if let disabledFillColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledFillColor) {
            self.disabledFillColor = disabledFillColor
        }
        
        if let disabledTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledTextColor) {
            self.disabledTextColor = disabledTextColor
        }
        
        if let disabledBorderColor = try typeContainer.decodeIfPresent(Color.self, forKey: .disabledBorderColor) {
            self.disabledBorderColor = disabledBorderColor
        }
    }
    
    open func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(moleculeName, forKey: .moleculeName)
        try container.encode(title, forKey: .title)
        try container.encode(enabled, forKey: .enabled)
        try container.encode(inverted, forKey: .inverted)
        try container.encodeModel(action, forKey: .action)
        try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
        try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
        try container.encodeIfPresent(accessibilityText, forKey: .accessibilityText)
        try container.encodeIfPresent(enabledFillColor, forKey: .fillColor)
        try container.encodeIfPresent(enabledTextColor, forKey: .textColor)
        try container.encodeIfPresent(enabledBorderColor, forKey: .borderColor)
        try container.encodeIfPresent(disabledFillColor, forKey: .disabledFillColor)
        try container.encodeIfPresent(disabledTextColor, forKey: .disabledTextColor)
        try container.encodeIfPresent(disabledBorderColor, forKey: .disabledBorderColor)
        try container.encodeIfPresent(style, forKey: .style)
        try container.encodeIfPresent(size, forKey: .size)
        try container.encodeIfPresent(groupName, forKey: .groupName)
    }
}
