//
// Copyright 2021 Signal Messenger, LLC
// SPDX-License-Identifier: AGPL-3.0-only
//

import SignalCoreKit

public protocol TextFieldWithPlaceholderDelegate: AnyObject {

    func textFieldDidBeginEditing(_ textField: UITextField)

    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool
}

// MARK: -

public class TextFieldWithPlaceholder: UIView {

    // MARK: - Public Properties

    public weak var delegate: TextFieldWithPlaceholderDelegate?

    public var placeholderText: String = "" {
        didSet {
            placeholderLabel.text = placeholderText
            textfield.accessibilityLabel = placeholderText
        }
    }

    public func acceptAutocorrectSuggestion() {
        textfield.acceptAutocorrectSuggestion()
    }

    public var text: String? {
        get { textfield.text?.nilIfEmpty }
        set {
            textfield.text = newValue
            updatePlaceholderVisibility()
        }
    }

    @discardableResult
    public override func becomeFirstResponder() -> Bool {
        textfield.becomeFirstResponder()
    }

    @discardableResult
    public override func resignFirstResponder() -> Bool {
        textfield.resignFirstResponder()
    }

    public override var canBecomeFirstResponder: Bool {
        textfield.canBecomeFirstResponder
    }

    public override var isFirstResponder: Bool {
        textfield.isFirstResponder
    }

    public var font: UIFont? {
        get { textfield.font }
        set { textfield.font = newValue }
    }

    // MARK: - Private Properties

    private lazy var textfield = UITextField()
    private lazy var placeholderLabel = UILabel()

    // MARK: - Lifecycle

    public override init(frame: CGRect) {
        super.init(frame: frame)
        applyTheme()

        textfield.delegate = self
        placeholderLabel.isUserInteractionEnabled = false

        // The placeholderLabel is perfectly aligned with the textView to allow for us to easily
        // hide/show placeholder text without needing to manipulate the text property of our primary
        // text view. This makes VoiceOver navigation by dragging a bit tricky, since a user won't be
        // able to find the placeholder text. Let's disable it in VoiceOver. Instead, placeholderText
        // will be an accessibility label on the primary text view.
        placeholderLabel.accessibilityElementsHidden = true

        // Layout + Constraints
        for subview in [textfield, placeholderLabel] {
            addSubview(subview)
            subview.autoPinEdgesToSuperviewEdges()
            subview.setCompressionResistanceHigh()
        }

        textfield.addTarget(self, action: #selector(textFieldDidChange), for: .editingChanged)

        NotificationCenter.default.addObserver(self, selector: #selector(applyTheme), name: .themeDidChange, object: nil)

        updatePlaceholderVisibility()
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    // MARK: -

    @objc
    private func textFieldDidChange(sender: UITextField) {
        Logger.info("")

        updatePlaceholderVisibility()
    }

    private func updatePlaceholderVisibility() {
        placeholderLabel.isHidden = text != nil
    }

    // MARK: - Private

    @objc
    private func applyTheme() {
        placeholderLabel.textColor = Theme.placeholderColor
        textfield.textColor = Theme.primaryTextColor
    }
}

// MARK: -

extension TextFieldWithPlaceholder: UITextFieldDelegate {
    public func textFieldDidBeginEditing(_ textField: UITextField) {
        delegate?.textFieldDidBeginEditing(textField)
    }

    public func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        delegate?.textField(textField, shouldChangeCharactersIn: range, replacementString: string) ?? true
    }
}
