package com.adealink.frame.imkit.utils.keyboard

import android.app.Activity
import android.content.Context
import android.os.Build
import android.provider.Settings
import com.adealink.frame.imkit.model.TAG_IM_KEYBOARD
import com.adealink.frame.log.Log
import java.lang.reflect.Method
import java.util.Locale

/**
 * The keyboard height provider, this class uses a PopupWindow to calculate the window height when
 * the floating keyboard is opened and closed.
 */
class KeyboardHeightProvider(activity: Activity) {
    private var floatKeyboardPresenter: KeyboardHeightPresenter? = null
    private val keyboardPresenter: KeyboardHeightPresenter
    private var openStatus: Boolean? = false
    private var keyboardHeight = 0
    private val internalObserver: KeyboardHeightObserver = object : KeyboardHeightObserver {
        override fun onKeyboardHeightChanged(
            orientation: Int, isOpen: Boolean, keyboardHeight: Int
        ) {
            val observer = observer ?: return
            if ((openStatus == null || isOpen != openStatus) || keyboardHeight != this@KeyboardHeightProvider.keyboardHeight) {
                openStatus = isOpen
                this@KeyboardHeightProvider.keyboardHeight = keyboardHeight
                observer.onKeyboardHeightChanged(orientation, isOpen, keyboardHeight)
            }
        }
    }
    private var observer: KeyboardHeightObserver? = null

    /**
     * Construct a new KeyboardHeightProvider
     *
     * @param activity The parent activity
     */
    init {
        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q && checkOverLayPermission(activity)) {
            // android 10 以下如果存在悬浮窗，且悬浮窗的 flag 包含 FLAG_ALT_FOCUSABLE_IM 时，通过 PopupWindow
            // 的方式测量键盘高度会失效，
            // 此时采用添加悬浮窗的形式来测量
            this.floatKeyboardPresenter = KeyboardHeightFloatImpl(activity)
            floatKeyboardPresenter?.setKeyboardHeightObserver(internalObserver)
        }
        this.keyboardPresenter = KeyboardHeightPopupImpl(activity)
        keyboardPresenter.setKeyboardHeightObserver(internalObserver)
    }

    fun start() {
        keyboardPresenter.start()
        floatKeyboardPresenter?.start()
    }

    fun stop() {
        keyboardPresenter.stop()
        floatKeyboardPresenter?.stop()
    }

    fun setKeyboardHeightObserver(observer: KeyboardHeightObserver?) {
        this.observer = observer
    }

    private fun checkOverLayPermission(context: Context): Boolean {
        var result = true
        val booleanValue: Boolean
        if (Build.VERSION.SDK_INT >= 23) {
            try {
                val method =
                    Settings::class.java.getDeclaredMethod("canDrawOverlays", Context::class.java) ?: return true
                booleanValue = method.invoke(null, *arrayOf<Any>(context)) as Boolean
                Log.i(TAG_IM_KEYBOARD, "isFloatWindowOpAllowed allowed: $booleanValue")
                return booleanValue
            } catch (e: NullPointerException) {
                return true
            } catch (e: Exception) {
                Log.e(
                    TAG_IM_KEYBOARD,
                    String.format(
                        "getDeclaredMethod:canDrawOverlays! Error:%s, etype:%s",
                        e.message, e.javaClass.canonicalName
                    )
                )
                return true
            }
        } else if (Build.BRAND.lowercase(Locale.getDefault()).contains("xiaomi")) {
            var method: Method?
            val systemService = context.getSystemService(Context.APP_OPS_SERVICE)
            try {
                method =
                    Class.forName("android.app.AppOpsManager")
                        .getMethod("checkOp", Integer.TYPE, Integer.TYPE, String::class.java)
            } catch (e: NoSuchMethodException) {
                Log.e(
                    TAG_IM_KEYBOARD,
                    String.format(
                        "NoSuchMethodException method:checkOp! Error:%s", e.message
                    )
                )
                method = null
            } catch (e: ClassNotFoundException) {
                Log.e(TAG_IM_KEYBOARD, "canDrawOverlays, e:${e.message}")
                method = null
            }
            if (method != null) {
                try {
                    val tmp =
                        method.invoke(
                            systemService,
                            *arrayOf<Any>(
                                24,
                                context.applicationInfo.uid,
                                context.packageName
                            )
                        ) as? Int
                    result = tmp != null && tmp == 0
                } catch (e: Exception) {
                    Log.e(
                        TAG_IM_KEYBOARD,
                        String.format(
                            "call checkOp failed: %s etype:%s",
                            e.message, e.javaClass.canonicalName
                        )
                    )
                }
            }
            Log.i(TAG_IM_KEYBOARD, "isFloatWindowOpAllowed allowed: $result")
            return result
        }
        return true
    }
}
