package com.kunzisoft.keepass.view

import android.content.Context
import android.os.Build
import android.text.InputFilter
import android.text.InputType
import android.text.method.PasswordTransformationMethod
import android.text.method.SingleLineTransformationMethod
import android.util.AttributeSet
import android.util.TypedValue
import android.view.View
import android.view.inputmethod.EditorInfo
import android.widget.LinearLayout
import androidx.annotation.DrawableRes
import androidx.appcompat.view.ContextThemeWrapper
import androidx.appcompat.widget.AppCompatImageButton
import androidx.core.content.ContextCompat
import androidx.core.view.ViewCompat
import androidx.core.view.isVisible
import com.google.android.material.textfield.TextInputEditText
import com.google.android.material.textfield.TextInputLayout
import com.kunzisoft.keepass.R

open class TextEditFieldView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0
) : ProtectedTextFieldView(context, attrs, defStyle) {

    private var labelViewId = ViewCompat.generateViewId()
    private var valueViewId = ViewCompat.generateViewId()
    protected var actionImageButtonId = ViewCompat.generateViewId()

    private val labelView = TextInputLayout(context).apply {
        layoutParams = LayoutParams(
                LayoutParams.MATCH_PARENT,
                LayoutParams.WRAP_CONTENT)
    }
    protected val valueView = TextInputEditText(
        ContextThemeWrapper(
            getContext(),
            R.style.KeepassDXStyle_TextInputLayout
        )
    ).apply {
        layoutParams = LinearLayout.LayoutParams(
                LayoutParams.MATCH_PARENT,
                LayoutParams.WRAP_CONTENT)
        inputType = EditorInfo.TYPE_TEXT_FLAG_NO_SUGGESTIONS
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            imeOptions = EditorInfo.IME_FLAG_NO_PERSONALIZED_LEARNING
            importantForAutofill = IMPORTANT_FOR_AUTOFILL_NO
        }
        importantForAccessibility = IMPORTANT_FOR_ACCESSIBILITY_NO
        maxLines = 1
    }
    private var actionImageButton = AppCompatImageButton(
            ContextThemeWrapper(
                context,
                R.style.KeepassDXStyle_ImageButton_Simple
            ), null, 0).apply {
        layoutParams = LayoutParams(
                LayoutParams.WRAP_CONTENT,
                LayoutParams.WRAP_CONTENT).also {
            it.topMargin = TypedValue.applyDimension(
                    TypedValue.COMPLEX_UNIT_DIP,
                    12f,
                    resources.displayMetrics
            ).toInt()
            it.addRule(ALIGN_PARENT_RIGHT)
            it.addRule(ALIGN_PARENT_END)
        }
        visibility = GONE
        contentDescription = context.getString(R.string.menu_edit)
    }

    init {
        // Manually write view to avoid view id bugs
        buildViews()
        labelView.addView(valueView)
        addView(labelView)
        addView(actionImageButton)
    }

    private fun buildViews() {
        labelView.apply {
            id = labelViewId
            layoutParams = (layoutParams as LayoutParams?)?.also {
                it.addRule(LEFT_OF, actionImageButtonId)
                it.addRule(START_OF, actionImageButtonId)
            }
        }
        valueView.apply {
            id = valueViewId
        }
        actionImageButton.apply {
            id = actionImageButtonId
        }
    }

    override fun applyFontVisibility(fontInVisibility: Boolean) {
        if (fontInVisibility)
            valueView.applyFontVisibility()
    }

    fun getActionImageView(): View {
        return actionImageButton
    }

    override var label: String
        get() {
            return labelView.hint?.toString() ?: ""
        }
        set(value) {
            labelView.hint = value
            // Define views Ids with label value
            labelViewId = "labelViewId $value".hashCode()
            valueViewId = "valueViewId $value".hashCode()
            actionImageButtonId = "actionImageButtonId $value".hashCode()
            buildViews()
        }

    override var value: CharArray
        get() {
            val charArray = CharArray(valueView.length())
            valueView.text?.getChars(0, valueView.length(), charArray, 0)
            return charArray
        }
        set(value) {
            valueView.setCharArray(value)
        }

    override var default: CharArray = CharArray(0)

    fun setMaxChars(numberChars: Int) {
        when {
            numberChars <= 0 -> {
                valueView.filters += InputFilter.LengthFilter(MAX_CHARS_LIMIT)
            }
            else -> {
                @Suppress("KotlinConstantConditions")
                val chars = if (numberChars > MAX_CHARS_LIMIT) MAX_CHARS_LIMIT else numberChars
                valueView.filters += InputFilter.LengthFilter(chars)
            }
        }
    }

    fun setMaxLines(numberLines: Int) {
        when {
            numberLines == 1 -> {
                valueView.inputType = valueView.inputType or
                    InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_VARIATION_NORMAL
                valueView.maxLines = 1
            }
            numberLines <= 0 -> {
                valueView.inputType = valueView.inputType or
                    InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
                valueView.maxLines = MAX_LINES_LIMIT
            }
            else -> {
                @Suppress("KotlinConstantConditions")
                val lines = if (numberLines > MAX_LINES_LIMIT) MAX_LINES_LIMIT else numberLines
                valueView.inputType = valueView.inputType or
                        InputType.TYPE_CLASS_TEXT or InputType.TYPE_TEXT_FLAG_MULTI_LINE
                valueView.maxLines = lines
            }
        }
    }

    override fun setProtection(
        protection: Boolean,
        isCurrentlyProtected: Boolean,
        onUnprotectClickListener: OnClickListener?
    ) {
        super.setProtection(protection, isCurrentlyProtected, onUnprotectClickListener)
        if (isProtected) {
            labelView.endIconMode = TextInputLayout.END_ICON_PASSWORD_TOGGLE
            // FIXME Called by itself during orientation change
            /*
            labelView.setEndIconOnClickListener {
                onUnprotectClickListener?.onClick(this@TextEditFieldView)
            }*/
        }
    }

    override fun changeProtectedValueParameters() {
        if (isCurrentlyProtected()) {
            valueView.inputType = valueView.inputType or InputType.TYPE_TEXT_VARIATION_PASSWORD
            valueView.transformationMethod = PasswordTransformationMethod.getInstance()
        } else {
            valueView.inputType = valueView.inputType or InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD
            valueView.transformationMethod = SingleLineTransformationMethod.getInstance()
        }
    }

    override fun setOnActionClickListener(onActionClickListener: OnClickListener?,
                                          @DrawableRes actionImageId: Int?) {
        actionImageId?.let {
            actionImageButton.setImageDrawable(ContextCompat.getDrawable(context, it))
        }
        actionImageButton.setOnClickListener(onActionClickListener)
        actionImageButton.visibility = if (onActionClickListener == null) GONE else VISIBLE
    }

    override var isFieldVisible: Boolean
        get() {
            return isVisible
        }
        set(value) {
            isVisible = value
        }

    companion object {
        const val MAX_CHARS_LIMIT = Integer.MAX_VALUE
        const val MAX_LINES_LIMIT = Integer.MAX_VALUE
    }
}
