package com.adealink.weparty.module.widget.form.adapter

import android.view.ViewGroup
import androidx.lifecycle.LifecycleOwner
import com.adealink.frame.log.Log
import com.adealink.weparty.module.widget.form.BaseWidgetView
import com.adealink.weparty.module.widget.form.IWidgetData
import com.adealink.weparty.module.widget.form.WidgetType
import com.adealink.weparty.module.widget.form.data.FieldException
import com.adealink.weparty.module.widget.form.data.StepField
import com.adealink.weparty.module.widget.form.field.multiplechoice.MultipleChoiceDelegate
import com.adealink.weparty.module.widget.form.field.multiplechoice.MultipleChoiceWidgetData
import com.adealink.weparty.module.widget.form.field.multipletext.MultipleTextDelegate
import com.adealink.weparty.module.widget.form.field.multipletext.MultipleTextWidgetData
import com.adealink.weparty.module.widget.form.field.number.NumberDelegate
import com.adealink.weparty.module.widget.form.field.number.NumberWidgetData
import com.adealink.weparty.module.widget.form.field.picture.PictureDelegate
import com.adealink.weparty.module.widget.form.field.picture.PictureWidgetData
import com.adealink.weparty.module.widget.form.field.singlechoice.SingleChoiceDelegate
import com.adealink.weparty.module.widget.form.field.singlechoice.SingleChoiceWidgetData
import com.adealink.weparty.module.widget.form.field.singletext.SingleTextDelegate
import com.adealink.weparty.module.widget.form.field.singletext.SingleTextWidgetData
import com.adealink.weparty.module.widget.form.field.voice.VoiceDelegate
import com.adealink.weparty.module.widget.form.field.voice.VoiceWidgetData

class StepWidgetAdapter {

    companion object {
        const val TAG = "StepWidgetAdapter"
    }

    private val types: Types = MutableTypes()

    inline fun <reified T : IWidgetData> register(delegate: WidgetDelegate<T, *>) {
        register(T::class.java, delegate)
    }

    fun <T : IWidgetData> register(clazz: Class<T>, delegate: WidgetDelegate<T, *>) {
        register(Type(clazz, delegate))
    }

    internal fun <T : IWidgetData> register(type: Type<T>) {
        types.register(type)
    }

    init {
        register(SingleTextDelegate())
        register(MultipleTextDelegate())
        register(SingleChoiceDelegate())
        register(MultipleChoiceDelegate())
        register(NumberDelegate())
        register(VoiceDelegate())
        register(PictureDelegate())
    }

    @Throws(FieldException::class)
    fun inflateWidget(
        lifecycleOwner: LifecycleOwner,
        parent: ViewGroup,
        fields: List<StepField<*>>
    ): List<BaseWidgetView<*>> {
        val widgets = fields.mapNotNull { field ->
            when (WidgetType.Companion.map(field.fieldType)) {
                WidgetType.UNKNOWN -> {
                    null
                }

                WidgetType.SINGLE_TEXT -> {
                    SingleTextWidgetData(field)
                }

                WidgetType.MULTIPLE_TEXT -> {
                    MultipleTextWidgetData(field)
                }

                WidgetType.SINGLE_CHOICE -> {
                    SingleChoiceWidgetData(field)
                }

                WidgetType.MULTIPLE_CHOICE -> {
                    MultipleChoiceWidgetData(field)
                }

                WidgetType.NUMBER -> {
                    NumberWidgetData(field)
                }

                WidgetType.PICTURE -> {
                    PictureWidgetData(field)
                }

                WidgetType.VOICE -> {
                    VoiceWidgetData(field)
                }
            }
        }
        val widgetList = mutableListOf<BaseWidgetView<*>>()
        for (widget in widgets) {
            findWidgetDelegate(widget)?.onCreateView(lifecycleOwner, parent.context, parent, widget)
                ?.let {
                    widgetList.add(it)
                }
        }
        return widgetList
    }

    internal fun <T : IWidgetData> findWidgetDelegate(widget: T): WidgetDelegate<T, *>? {
        val index = types.firstIndexOf(widget.javaClass)
        if (index != -1) {
            return types.getType<T>(index).delegate
        }
        Log.e(TAG, "findWidgetDelegate fail, widget:$widget")
        return null
    }


}