//
//  EntryFieldModel.swift
//  MVMCoreUI
//
//  Created by Kevin Christiano on 1/22/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import Foundation


@objcMembers open class EntryFieldModel: MoleculeModelProtocol, FormFieldProtocol, FormRuleWatcherFieldProtocol, UIUpdatableModelProtocol, ClearableModelProtocol {
    
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    public class var identifier: String { "" }
    
    public var backgroundColor: Color?
    public var accessibilityIdentifier: String?
    public var shouldClearText: Bool = false
    public var dynamicErrorMessage: String? {
        didSet {
            isValid = dynamicErrorMessage?.isEmpty ?? true
            updateUIDynamicError?()
        }
    }
    public var errorMessage: String?
    public var errorTextColor: Color?
    public var enabled: Bool = true
    public var required: Bool = true
    public var readOnly: Bool = false
    public var showError: Bool?
    public var hideBorders = false
    public var locked: Bool?
    public var selected: Bool?
    public var text: String?
    public var fieldKey: String?
    public var groupName: String = FormValidator.defaultGroupName
    public var baseValue: AnyHashable?
    public var wasInitiallySelected: Bool = false
    public var title: String?
    public var feedback: String?

    //used to drive the EntryFieldView UI
    public var titleStateLabel: FormLabelModel
    public var feedbackStateLabel: FormLabelModel

    public var isValid: Bool? = true {
        didSet { updateUI?() }
    }
    
    /// Temporary binding mechanism for the view to update on enable changes.
    public var updateUI: ActionBlock?
    
    // TODO: Remove once updateUI is fixed with isSelected
    public var updateUIDynamicError: ActionBlock?
    
    //--------------------------------------------------
    // MARK: - Keys
    //--------------------------------------------------
    
    private enum CodingKeys: String, CodingKey {
        case moleculeName
        case backgroundColor
        case accessibilityIdentifier
        case title
        case enabled
        case readOnly
        case feedback
        case errorMessage
        case errorTextColor
        case locked
        case selected
        case showError
        case hideBorders
        case text
        case fieldKey
        case groupName
        case required
    }
    
    //--------------------------------------------------
    // MARK: - Validation Methods
    //--------------------------------------------------
    
    public func formFieldValue() -> AnyHashable? {
        guard enabled else { return nil }
        
        if dynamicErrorMessage != nil {
            dynamicErrorMessage = nil
        }
        return text
    }
    
    public func setValidity(_ valid: Bool, rule: RulesProtocol) {
        
        if let fieldKey = fieldKey, let ruleErrorMessage = rule.errorMessage?[fieldKey] {
            self.errorMessage = ruleErrorMessage
        }
        
        self.isValid = valid
        updateUI?()
    }

    //--------------------------------------------------
    // MARK: - Initializers
    //--------------------------------------------------
    
    public init(with text: String) {
        self.text = text
        baseValue = text
        self.titleStateLabel = FormLabelModel(text: "")
        self.feedbackStateLabel = FormLabelModel(text: "")
    }
    
    //--------------------------------------------------
    // MARK: - Initializers
    //--------------------------------------------------
    public func clear() {
        self.text = ""
    }
    
    //--------------------------------------------------
    // 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)
        title = try typeContainer.decodeIfPresent(String.self, forKey: .title)
        feedback = try typeContainer.decodeIfPresent(String.self, forKey: .feedback)
        errorMessage = try typeContainer.decodeIfPresent(String.self, forKey: .errorMessage)
        errorTextColor = try typeContainer.decodeIfPresent(Color.self, forKey: .errorTextColor)
        enabled = try typeContainer.decodeIfPresent(Bool.self, forKey: .enabled) ?? true
        required = try typeContainer.decodeIfPresent(Bool.self, forKey: .required) ?? true
        readOnly = try typeContainer.decodeIfPresent(Bool.self, forKey: .readOnly) ?? false
        locked = try typeContainer.decodeIfPresent(Bool.self, forKey: .locked)
        selected = try typeContainer.decodeIfPresent(Bool.self, forKey: .selected)
        text = try typeContainer.decodeIfPresent(String.self, forKey: .text)
        hideBorders = try typeContainer.decodeIfPresent(Bool.self, forKey: .hideBorders) ?? false
        baseValue = text
        fieldKey = try typeContainer.decodeIfPresent(String.self, forKey: .fieldKey)
        if let groupName = try typeContainer.decodeIfPresent(String.self, forKey: .groupName) {
            self.groupName = groupName
        }
        self.titleStateLabel = FormLabelModel(text: title ?? "")
        self.feedbackStateLabel = FormLabelModel(model: LabelModel(text: feedback ?? "",
                                                                    fontStyle: FormLabelModel.defaultFontStyle,
                                                                    textColor: Color(uiColor: .mvmCoolGray6)))
    }
    
    public func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encodeIfPresent(moleculeName, forKey: .moleculeName)
        try container.encodeIfPresent(backgroundColor, forKey: .backgroundColor)
        try container.encodeIfPresent(accessibilityIdentifier, forKey: .accessibilityIdentifier)
        try container.encodeIfPresent(title, forKey: .title)
        try container.encodeIfPresent(feedback, forKey: .feedback)
        try container.encodeIfPresent(text, forKey: .text)
        try container.encodeIfPresent(locked, forKey: .locked)
        try container.encodeIfPresent(showError, forKey: .showError)
        try container.encodeIfPresent(selected, forKey: .selected)
        try container.encodeIfPresent(errorTextColor, forKey: .errorTextColor)
        try container.encodeIfPresent(errorMessage, forKey: .errorMessage)
        try container.encodeIfPresent(fieldKey, forKey: .fieldKey)
        try container.encodeIfPresent(groupName, forKey: .groupName)
        
        try container.encode(readOnly, forKey: .readOnly)
        try container.encode(enabled, forKey: .enabled)
        try container.encode(required, forKey: .required)
        try container.encode(hideBorders, forKey: .hideBorders)
    }
}
