package com.lukouguoji.module_base.base

import android.content.Context
import android.content.DialogInterface
import android.view.Gravity
import android.view.LayoutInflater
import androidx.databinding.DataBindingUtil
import androidx.databinding.ViewDataBinding
import com.lukouguoji.module_base.interfaces.IGetData
import com.lukouguoji.module_base.ktx.getLifecycleOwner
import com.lukouguoji.module_base.ktx.loge
import com.lxj.xpopup.XPopup
import com.lxj.xpopup.core.AttachPopupView
import com.lxj.xpopup.core.BasePopupView
import com.lxj.xpopup.core.BottomPopupView
import com.lxj.xpopup.core.CenterPopupView
import com.lxj.xpopup.core.DrawerPopupView
import com.lxj.xpopup.core.FullScreenDialog
import com.lxj.xpopup.impl.FullScreenPopupView
import dev.DevUtils
import dev.utils.common.ReflectUtils
import kotlin.properties.Delegates

/**
 * @author：孟凡华
 * @date：2022/8/24
 * @desc：
 */
abstract class BaseDialogModel<T : ViewDataBinding>(
    private val dialogType: Int = DIALOG_TYPE_BOTTOM,
) : IGetData {

    //布局
    protected var binding: T by Delegates.notNull()

    //弹窗
    protected var dialog: BasePopupView? = null

    //消失监听
    private var dismissListener: DialogInterface.OnDismissListener? = null

    /**
     * 设置关闭监听
     */
    fun setOnDismissListener(listener: DialogInterface.OnDismissListener) {
        dismissListener = listener
    }

    //展示弹窗
    open fun show(context: Context = DevUtils.getTopActivity()) {
        if (dialog == null) {
            createDialog(context)
        }
        getData()
    }

    /**
     * 获取数据并展示弹窗
     * 弹窗系统在布局高度需要延时请求的数据填充确定时,会出现高度异常的情况
     * 该方法旨在开发者在延时请求的数据获取到后,再自己处理弹窗的展示逻辑,可以有效避免高度异常的问题
     * 如果高度固定,则不需要处理
     */
    override fun getData() {
        dialog?.show()
    }

    //关闭弹窗
    open fun dismiss() {
        dialog?.dismiss()
    }

    /**
     * 当弹窗关闭处理
     */
    open fun onDismiss(d: DialogInterface?) {
        dismissListener?.onDismiss(d)
    }

    //创建弹窗
    private fun createDialog(context: Context) {
        // 创建弹窗View
        val basePopupView = when (dialogType) {
            // 底部弹窗
            DIALOG_TYPE_BOTTOM -> {
                createBottomPopupView(context)
            }
            // 中间弹窗
            DIALOG_TYPE_CENTER -> {
                createCenterPopupView(context)
            }
            // 抽屉弹窗
            DIALOG_TYPE_DRAWER -> {
                createDrawerPopupView(context)
            }
            // 绑定弹窗
            DIALOG_TYPE_ATTACH -> {
                createAttachPopupView(context)
            }
            // 全屏
            DIALOG_TYPE_FULL -> {
                createFullPopupView(context)
            }
            // 其他(默认底部弹窗)
            else -> {
                createBottomPopupView(context)
            }
        }

        // 构建弹窗
        val builder = XPopup.Builder(context)
        // 构建中
        onBuild(builder)
        // 创建弹窗
        dialog = builder.asCustom(basePopupView)

        // 弹窗创建完成
        onDialogCreated(context)
    }

    /**
     * 创建中间弹窗视图
     */
    private fun createCenterPopupView(context: Context): BasePopupView {
        val basePop = object : CenterPopupView(context) {
            override fun addInnerContent() {
                binding = DataBindingUtil.inflate<T>(
                    LayoutInflater.from(context),
                    layoutId(),
                    centerPopupContainer,
                    false
                )
                binding.lifecycleOwner = context.getLifecycleOwner()
                contentView = binding.root
                val params = contentView.layoutParams as LayoutParams
                params.gravity = Gravity.CENTER
                centerPopupContainer.addView(contentView, params)
            }

            override fun getImplLayoutId(): Int {
                return layoutId()
            }

            override fun onDismiss() {
                super.onDismiss()
                this@BaseDialogModel.onDismiss(null)
            }
        }
        ReflectUtils.reflect(basePop)
            .method("addInnerContent")

        return basePop
    }

    /**
     * 创建底部弹窗视图
     */
    private fun createBottomPopupView(context: Context): BasePopupView {
        val basePop: BottomPopupView = object : BottomPopupView(context) {
            override fun addInnerContent() {
                binding = DataBindingUtil.inflate<T>(
                    LayoutInflater.from(context),
                    layoutId(),
                    bottomPopupContainer,
                    false
                )
                binding.lifecycleOwner = context.getLifecycleOwner()
                bottomPopupContainer.addView(binding.root)
            }

            override fun getImplLayoutId(): Int {
                return layoutId()
            }

            override fun onDismiss() {
                super.onDismiss()
                this@BaseDialogModel.onDismiss(null)
            }
        }
        ReflectUtils.reflect(basePop)
            .method("addInnerContent")
        return basePop
    }

    /**
     * 创建drawer
     */
    private fun createDrawerPopupView(context: Context): BasePopupView {
        val basePop = object : DrawerPopupView(context) {
            override fun addInnerContent() {
                binding = DataBindingUtil.inflate<T>(
                    LayoutInflater.from(context),
                    layoutId(),
                    drawerContentContainer,
                    false
                )
                binding.lifecycleOwner = context.getLifecycleOwner()
                drawerContentContainer.addView(binding.root)
            }

            override fun getImplLayoutId() = layoutId()

            override fun onDismiss() {
                super.onDismiss()
                this@BaseDialogModel.onDismiss(null)
            }
        }
        ReflectUtils.reflect(basePop)
            .method("addInnerContent")

        return basePop
    }

    /**
     * 创建Attach
     */
    private fun createAttachPopupView(context: Context): BasePopupView {
        val basePop = object : AttachPopupView(context) {
            override fun addInnerContent() {
                binding = DataBindingUtil.inflate<T>(
                    LayoutInflater.from(context),
                    layoutId(),
                    attachPopupContainer,
                    false
                )
                binding.lifecycleOwner = context.getLifecycleOwner()
                attachPopupContainer.addView(binding.root)
            }

            override fun getImplLayoutId() = layoutId()

            override fun onDismiss() {
                super.onDismiss()
                this@BaseDialogModel.onDismiss(null)
            }
        }
        ReflectUtils.reflect(basePop)
            .method("addInnerContent")

        return basePop
    }

    /**
     * 创建Attach
     */
    private fun createFullPopupView(context: Context): BasePopupView {
        val basePop = object : FullScreenPopupView(context) {
            override fun addInnerContent() {
                binding = DataBindingUtil.inflate<T>(
                    LayoutInflater.from(context),
                    layoutId(),
                    fullPopupContainer,
                    false
                )
                binding.lifecycleOwner = context.getLifecycleOwner()
                fullPopupContainer.addView(binding.root)
            }

            override fun getImplLayoutId() = layoutId()

            override fun onDismiss() {
                super.onDismiss()
                this@BaseDialogModel.onDismiss(null)
            }
        }
        ReflectUtils.reflect(basePop)
            .method("addInnerContent")

        return basePop
    }

    /**
     * 构建时处理
     */
    open fun onBuild(builder: XPopup.Builder) {
    }

    //弹窗布局ID
    abstract fun layoutId(): Int

    //dialog创建后
    abstract fun onDialogCreated(context: Context)

    /**
     * 是否展示中
     */
    fun isShowing() = dialog?.isShow ?: false

    fun release() {
        dismiss()
        dialog = null
        dismissListener = null
    }

    companion object {
        //底部弹窗
        const val DIALOG_TYPE_BOTTOM = 0

        //居中弹窗
        const val DIALOG_TYPE_CENTER = 1

        //抽屉 弹窗
        const val DIALOG_TYPE_DRAWER = 2

        //attach弹窗
        const val DIALOG_TYPE_ATTACH = 3

        //全屏
        const val DIALOG_TYPE_FULL = 4
    }
}