package com.adealink.weparty.commonui.toast

import android.annotation.SuppressLint
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.widget.Toast
import androidx.annotation.DrawableRes
import androidx.appcompat.widget.AppCompatImageView
import androidx.appcompat.widget.AppCompatTextView
import com.adealink.weparty.R
import com.adealink.weparty.commonui.ext.dp
import java.lang.ref.WeakReference

private const val ATOMIC_EVENT_ID = 100011
private const val FRAMEWORK_NAME = "AtomicXCore"

object ToastCompat {

    enum class Style {
        TEXT,
        INFO,
        HELP,
        LOADING,
        SUCCESS,
        WARNING,
        ERROR
    }

    enum class Position {
        TOP,
        CENTER,
        BOTTOM
    }

    enum class Duration(val value: Int) {
        SHORT(Toast.LENGTH_SHORT),
        LONG(Toast.LENGTH_LONG);

        companion object {
            @JvmStatic
            fun map(duration: Int): Duration {
                return entries.find { it.value == duration } ?: SHORT
            }
        }
    }

    private var toastRef: WeakReference<Toast>? = null
    private var layoutRef: WeakReference<View>? = null

    private val mainHandler = Handler(Looper.getMainLooper())
    private var pendingTask: Runnable? = null

    fun show(
        context: Context,
        text: String,
        style: Style = Style.TEXT,
        position: Position = Position.CENTER,
        @DrawableRes customIcon: Int? = null,
        duration: Duration = Duration.SHORT,
        code: Int? = null,
        extensionInfo: Map<String, Any>? = null
    ) {
        if (text.isBlank()) return

        pendingTask?.let {
            mainHandler.removeCallbacks(it)
            pendingTask = null
        }

        val appContext = context.applicationContext

        val task = object : Runnable {
            override fun run() {
                executeRealShow(appContext, text, style, position, customIcon, duration)
                if (pendingTask === this) {
                    pendingTask = null
                }
            }
        }
        pendingTask = task
        mainHandler.postDelayed(task, 50)
    }

    private fun executeRealShow(
        appContext: Context,
        text: String,
        style: Style,
        position: Position,
        @DrawableRes customIcon: Int?,
        duration: Duration,
    ) {

        var toast = toastRef?.get()
        var layout = layoutRef?.get()

        if (toast == null || layout == null) {
            layout = LayoutInflater.from(appContext).inflate(R.layout.layout_compat_toast, null)
            toast = Toast(appContext)

            @Suppress("DEPRECATION")
            toast.view = layout

            layoutRef = WeakReference(layout)
            toastRef = WeakReference(toast)
        }

        applyDesignTokens(layout, text, style, customIcon)

        toast.apply {
            this.duration = duration.value
            val gravity = when (position) {
                Position.TOP -> Gravity.TOP or Gravity.CENTER_HORIZONTAL
                Position.CENTER -> Gravity.CENTER
                Position.BOTTOM -> Gravity.BOTTOM or Gravity.CENTER_HORIZONTAL
            }
            setGravity(gravity, 0, if (position == Position.CENTER) 0 else 24.dp())
            show()
        }
    }

    @SuppressLint("SetTextI18n")
    private fun applyDesignTokens(
        container: View,
        text: String,
        style: Style,
        @DrawableRes customIcon: Int?,
    ) {
        val iconView = container.findViewById<AppCompatImageView>(R.id.iv_toast)
        val textView = container.findViewById<AppCompatTextView>(R.id.tv_toast)

        textView.text = text
        val iconRes = customIcon ?: resolveIconRes(style)
        if (iconRes != null) {
            iconView.visibility = View.VISIBLE
            iconView.setImageResource(iconRes)
        } else {
            iconView.visibility = View.GONE
        }
    }

    @DrawableRes
    private fun resolveIconRes(style: Style): Int? {
        return when (style) {
            Style.WARNING -> R.drawable.common_toast_warming_ic
            else -> null
        }
    }
}