package com.topjohnwu.magisk.view

import android.content.Context
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.graphics.drawable.Drawable
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import androidx.annotation.DrawableRes
import androidx.annotation.StringRes
import androidx.appcompat.app.AlertDialog
import androidx.databinding.ViewDataBinding
import com.topjohnwu.magisk.BR
import com.topjohnwu.magisk.databinding.DialogMagiskBaseBinding
import com.topjohnwu.magisk.utils.KObservableField

class MagiskDialog @JvmOverloads constructor(
    context: Context, theme: Int = 0
) : AlertDialog(context, theme) {

    private val binding: DialogMagiskBaseBinding =
        DialogMagiskBaseBinding.inflate(LayoutInflater.from(context))
    private val data = Data()

    init {
        binding.setVariable(BR.data, data)
        super.setView(binding.root)
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
    }

    inner class Data {
        val icon = KObservableField(0)
        val iconRaw = KObservableField<Drawable?>(null)
        val title = KObservableField<CharSequence>("")
        val message = KObservableField<CharSequence>("")

        val buttonPositive = Button()
        val buttonNeutral = Button()
        val buttonNegative = Button()
        val buttonIDGAF = Button()
    }

    enum class ButtonType {
        POSITIVE, NEUTRAL, NEGATIVE, IDGAF
    }

    inner class Button {
        val icon = KObservableField(0)
        val title = KObservableField<CharSequence>("")
        val isEnabled = KObservableField(true)

        var onClickAction: OnDialogButtonClickListener = {}
        var preventDismiss = false

        fun clicked() {
            //we might not want the click to dismiss the button to begin with
            var prevention = preventDismiss

            onClickAction(this@MagiskDialog)

            //in case we don't want the dialog to close after clicking the button
            //ie. the input is incorrect ...
            //otherwise we disregard the request, bcs it just might reset the button in the new
            //instance
            if (preventDismiss) {
                prevention = preventDismiss
            }

            if (!prevention) {
                dismiss()
            }
        }
    }

    inner class ButtonBuilder(private val button: Button) {
        var icon: Int
            get() = button.icon.value
            set(value) {
                button.icon.value = value
            }
        var title: CharSequence
            get() = button.title.value
            set(value) {
                button.title.value = value
            }
        var titleRes: Int
            get() = 0
            set(value) {
                button.title.value = context.getString(value)
            }
        var isEnabled: Boolean
            get() = button.isEnabled.value
            set(value) {
                button.isEnabled.value = value
            }
        var preventDismiss: Boolean
            get() = button.preventDismiss
            set(value) {
                button.preventDismiss = value
            }

        fun onClick(listener: OnDialogButtonClickListener) {
            button.onClickAction = listener
        }
    }

    fun applyTitle(@StringRes stringRes: Int) =
        apply { data.title.value = context.getString(stringRes) }

    fun applyTitle(title: CharSequence) =
        apply { data.title.value = title }

    fun applyMessage(@StringRes stringRes: Int, vararg args: Any) =
        apply { data.message.value = context.getString(stringRes, *args) }

    fun applyMessage(message: CharSequence) =
        apply { data.message.value = message }

    fun applyIcon(@DrawableRes drawableRes: Int) =
        apply { data.icon.value = drawableRes }

    fun applyIcon(drawable: Drawable) =
        apply { data.iconRaw.value = drawable }

    fun applyButton(buttonType: ButtonType, builder: ButtonBuilder.() -> Unit) = apply {
        val button = when (buttonType) {
            ButtonType.POSITIVE -> data.buttonPositive
            ButtonType.NEUTRAL -> data.buttonNeutral
            ButtonType.NEGATIVE -> data.buttonNegative
            ButtonType.IDGAF -> data.buttonIDGAF
        }
        ButtonBuilder(button).apply(builder)
    }

    fun cancellable(isCancellable: Boolean) = apply {
        setCancelable(isCancellable)
    }

    fun <Binding : ViewDataBinding> applyView(binding: Binding, body: Binding.() -> Unit = {}) =
        apply {
            resetView()
            this.binding.dialogBaseContainer.addView(binding.root)
            binding.apply(body)
        }

    fun applyView(view: View) = apply {
        resetView()
        this.binding.dialogBaseContainer.addView(view)
    }

    fun onDismiss(callback: OnDialogButtonClickListener) =
        apply { setOnDismissListener(callback) }

    fun onShow(callback: OnDialogButtonClickListener) =
        apply { setOnShowListener(callback) }

    fun reveal() = apply { super.show() }

    // ---

    fun resetView() = apply {
        binding.dialogBaseContainer.removeAllViews()
    }

    fun resetTitle() = applyTitle("")
    fun resetMessage() = applyMessage("")
    fun resetIcon() = applyIcon(0)

    fun resetButtons() = apply {
        ButtonType.values().forEach {
            applyButton(it) {
                title = ""
                icon = 0
                isEnabled = true
                preventDismiss = false
                onClick {}
            }
        }
    }

    fun reset() = resetTitle()
        .resetMessage()
        .resetView()
        .resetIcon()
        .resetButtons()

    //region Deprecated Members
    @Deprecated("Use applyTitle instead", ReplaceWith("applyTitle"))
    override fun setTitle(title: CharSequence?) = Unit

    @Deprecated("Use applyTitle instead", ReplaceWith("applyTitle"))
    override fun setTitle(titleId: Int) = Unit

    @Deprecated("Use reveal()", ReplaceWith("reveal()"))
    override fun show() {
    }
    //endregion
}

typealias OnDialogButtonClickListener = (DialogInterface) -> Unit