//
//  TextViewEntryField.swift
//  MVMCoreUI
//
//  Created by Kevin Christiano on 5/7/20.
//  Copyright © 2020 Verizon Wireless. All rights reserved.
//

import UIKit


class TextViewEntryField: EntryField, UITextViewDelegate, ObservingTextFieldDelegate {
    //--------------------------------------------------
    // MARK: - Outlets
    //--------------------------------------------------
    
    open private(set) var textView: TextView = {
        let textView = TextView()
        textView.setContentCompressionResistancePriority(.required, for: .vertical)
        return textView
    }()
    
    //--------------------------------------------------
    // MARK: - Properties
    //--------------------------------------------------
    
    private var observingForChange: Bool = false
    
    //--------------------------------------------------
    // MARK: - Computed Properties
    //--------------------------------------------------
    
    public var textViewEntryFieldModel: TextViewEntryFieldModel? {
        model as? TextViewEntryFieldModel
    }
    
    public override var isEnabled: Bool {
        get { super.isEnabled }
        set (enabled) {
            super.isEnabled = enabled
            
            DispatchQueue.main.async { [weak self] in
                guard let self = self else { return }
                
                self.textView.isEnabled = enabled
                if self.textView.isShowingPlaceholder {
                    self.textView.textColor = self.textView.placeholderTextColor
                } else {
                    self.textView.textColor = (self.textView.isEnabled ? self.textViewEntryFieldModel?.enabledTextColor : self.textViewEntryFieldModel?.disabledTextColor)?.uiColor
                }
            }
        }
    }
    
    public override var showError: Bool {
        get { super.showError }
        set (error) {
            
            if error {
                textView.accessibilityValue = String(format: MVMCoreUIUtility.hardcodedString(withKey: "textView_error_message") ?? "", textView.text ?? "", entryFieldModel?.errorMessage ?? "")
            } else {
                textView.accessibilityValue = nil
            }
            
            super.showError = error
        }
    }
    
    /// The text of this textView.
    open override var text: String? {
        get { textViewEntryFieldModel?.text }
        set {
            textView.text = newValue
            textViewEntryFieldModel?.text = newValue
        }
    }
    
    /// Placeholder access for the textView.
    public var placeholder: String? {
        get { textViewEntryFieldModel?.placeholder }
        set {
            textView.placeholder = newValue ?? ""
            textViewEntryFieldModel?.placeholder = newValue
            textView.setPlaceholderIfAvailable()
        }
    }
    
    //--------------------------------------------------
    // MARK: - Constraint
    //--------------------------------------------------
    
    public var heightConstraint: NSLayoutConstraint?
    private var topConstraint: NSLayoutConstraint?
    private var leadingConstraint: NSLayoutConstraint?
    private var trailingConstraint: NSLayoutConstraint?
    private var bottomConstraint: NSLayoutConstraint?
    
    private func adjustMarginConstraints(constant: CGFloat) {
        
        topConstraint?.constant = constant
        leadingConstraint?.constant = constant
        trailingConstraint?.constant = constant
        bottomConstraint?.constant = constant
    }
    
    //--------------------------------------------------
    // MARK: - Delegate Properties
    //--------------------------------------------------
    
    /// The delegate and block for validation. Validates if the text that the user has entered.
    public weak var observingTextViewDelegate: ObservingTextFieldDelegate? {
        didSet {
            if observingTextViewDelegate != nil && !observingForChange {
                observingForChange = true
                NotificationCenter.default.addObserver(self, selector: #selector(valueChanged), name: UITextView.textDidChangeNotification, object: textView)
                NotificationCenter.default.addObserver(self, selector: #selector(endInputing), name: UITextView.textDidEndEditingNotification, object: textView)
                NotificationCenter.default.addObserver(self, selector: #selector(startEditing), name: UITextView.textDidBeginEditingNotification, object: textView)
                
            } else if observingTextViewDelegate == nil && observingForChange {
                observingForChange = false
                NotificationCenter.default.removeObserver(self, name: UITextView.textDidChangeNotification, object: textView)
                NotificationCenter.default.removeObserver(self, name: UITextView.textDidEndEditingNotification, object: textView)
                NotificationCenter.default.removeObserver(self, name: UITextView.textDidBeginEditingNotification, object: textView)
            }
        }
    }
    
    /// If you're using a ViewController, you must set this to it
    public weak var uiTextViewDelegate: UITextViewDelegate? {
        get { textView.delegate }
        set { textView.delegate = newValue }
    }
    
    @objc public func setBothTextDelegates(to delegate: (UITextViewDelegate & ObservingTextFieldDelegate)?) {
        observingTextViewDelegate = delegate
        uiTextViewDelegate = delegate
    }
    
    open func setupTextViewToolbar() {
        let observingDelegate = observingTextViewDelegate ?? self
        textView.inputAccessoryView = UIToolbar.getToolbarWithDoneButton(delegate: observingDelegate,
                                                                         action: #selector(observingDelegate.dismissFieldInput))
    }
    
    //--------------------------------------------------
    // MARK: - Lifecycle
    //--------------------------------------------------
    
    @objc open override func setupFieldContainerContent(_ container: UIView) {
        
        container.addSubview(textView)
        
        topConstraint = textView.topAnchor.constraint(equalTo: container.topAnchor, constant: Padding.Three)
        leadingConstraint = textView.leadingAnchor.constraint(equalTo: container.leadingAnchor, constant: Padding.Three)
        trailingConstraint = container.trailingAnchor.constraint(equalTo: textView.trailingAnchor, constant: Padding.Three)
        bottomConstraint = container.bottomAnchor.constraint(equalTo: textView.bottomAnchor, constant: Padding.Three)
        
        topConstraint?.isActive = true
        leadingConstraint?.isActive = true
        trailingConstraint?.isActive = true
        bottomConstraint?.isActive = true
        
        heightConstraint = textView.heightAnchor.constraint(equalToConstant: 0)
        accessibilityElements = [titleLabel, textView, feedbackLabel]
    }
    
    open override func updateView(_ size: CGFloat) {
        super.updateView(size)
        textView.updateView(size)
    }
    
    open override func reset() {
        super.reset()
        
        textView.reset()
        adjustMarginConstraints(constant: Padding.Three)
        heightConstraint?.constant = 0
        heightConstraint?.isActive = false
    }
    
    //--------------------------------------------------
    // MARK: - Methods
    //--------------------------------------------------
    
    /// Validates the text of the entry field.
    @objc public override func validateText() {
        text = textView.text
        super.validateText()
    }
    
    /// Executes on UITextView.textDidBeginEditingNotification
    @objc override func startEditing() {
        super.startEditing()
        _ = textView.becomeFirstResponder()
    }
    
    /// Executes on UITextView.textDidChangeNotification (each character entry)
    @objc override func valueChanged() {
        super.valueChanged()
        validateText()
    }
    
    /// Executes on UITextView.textDidEndEditingNotification
    @objc override func endInputing() {
        super.endInputing()
        
        // Don't show error till user starts typing.
        guard text?.count ?? 0 != 0 else {
            showError = false
            return
        }
        
        if let isValid = textViewEntryFieldModel?.isValid {
            self.isValid = isValid
        }
        
        showError = !isValid
    }
    
    //--------------------------------------------------
    // MARK: - MoleculeViewProtocol
    //--------------------------------------------------
    
    open override func set(with model: MoleculeModelProtocol, _ delegateObject: MVMCoreUIDelegateObject?, _ additionalData: [AnyHashable: Any]?) {
        super.set(with: model, delegateObject, additionalData)
        
        guard let model = model as? TextViewEntryFieldModel else { return }
        
        if let height = model.height {
            heightConstraint?.constant = height
            heightConstraint?.isActive = true
        }
        
        text = model.text
        uiTextViewDelegate = delegateObject?.uiTextViewDelegate
        observingTextViewDelegate = delegateObject?.observingTextFieldDelegate
        
        if let accessibilityText = model.accessibilityText {
            accessibilityLabel = accessibilityText
        }
        
        textView.isEditable = model.editable
        textView.textAlignment = model.textAlignment
        textView.accessibilityIdentifier = model.accessibilityIdentifier
        textView.textColor = model.enabled ? model.enabledTextColor.uiColor : model.disabledTextColor.uiColor
        textView.font = model.fontStyle.getFont()
        textView.placeholder = model.placeholder ?? ""
        textView.placeholderFontStyle = model.placeholderFontStyle
        textView.placeholderTextColor = model.placeholderTextColor.uiColor
        textView.setPlaceholderIfAvailable()
        
        switch model.type {
        case .secure, .password:
            textView.isSecureTextEntry = true
            
        case .numberSecure:
            textView.isSecureTextEntry = true
            textView.keyboardType = .numberPad
            
        case .number:
            textView.keyboardType = .numberPad
            
        case .email:
            textView.keyboardType = .emailAddress
            
        default: break
        }
        
        /// No point in configuring if the TextView is Read-only.
        if textView.isEditable {
            FormValidator.setupValidation(for: model, delegate: delegateObject?.formHolderDelegate)
            setupTextViewToolbar()
            
            if isSelected {
                DispatchQueue.main.async {
                    _ = self.textView.becomeFirstResponder()
                }
            }
        }
        
        if model.hideBorders {
            adjustMarginConstraints(constant: 0)
        }
        
    }
}
