package cn.yyxx.eyuancomm.impl.channel.huawei.floatview

import android.app.Activity
import android.content.Context
import android.graphics.PixelFormat
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.view.*
import android.view.WindowManager.LayoutParams.FLAG_FULLSCREEN
import android.widget.FrameLayout
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.PopupWindow
import cn.yyxx.support.DensityUtils
import cn.yyxx.support.scheduler.ScheduledWorker
import java.util.concurrent.TimeUnit
import kotlin.math.abs


/**
 * @author #Suyghur.
 * Created on 2021/06/30
 */
class FloatBall(val activity: Activity, private val isLandscape: Boolean, private val callback: FloatBallCallback) : FrameLayout(activity),
    View.OnTouchListener {

    private lateinit var wm: WindowManager
    private lateinit var wlp: WindowManager.LayoutParams

    private lateinit var rootLinearLayout: LinearLayout
    private lateinit var frameLayout: FrameLayout
    private lateinit var ballView: ImageView
    private lateinit var ballMenu: FloatBallMenu
    private lateinit var menu: PopupWindow

    //浮标是否移动
    private var isMove = false

    //手指按下时坐标
    private var mTouchStartX = 0f
    private var mTouchStartY = 0f

    //是否展开
    private var hasShowContent = false

    //当前贴边状态
    private var isHide = false

    //默认吸附在左边
    private var isLeftLocation = true

    //菜单menu的长度
    private var mSize = 0

    private var hasStatusBar = false

    private var displayWorker: ScheduledWorker? = null

    private val timerHandler = object : Handler(Looper.getMainLooper()) {
        override fun handleMessage(msg: Message) {
            when (msg.what) {
                1000 -> {
                    invokeBallFullOrHalt(true)
                    callback.onUpdateBallView(ballView, isLeftLocation, true)
                    //把worker取消掉防止一直在执行
                    displayWorker?.cancel()
                }
            }
        }
    }

    init {
        hasStatusBar = activity.window.attributes.flags and FLAG_FULLSCREEN != FLAG_FULLSCREEN
        createWM()
        createView()
        addView(rootLinearLayout)
        wm.addView(this, wlp)
        displayWorker = ScheduledWorker(1)
        invokeDisplayTimerWork()
    }

    private fun createWM() {
        wm = activity.windowManager
        wlp = WindowManager.LayoutParams()
        wlp.apply {
            //总是出现在应用程序窗口之上
            type = WindowManager.LayoutParams.LAST_APPLICATION_WINDOW
            format = PixelFormat.RGBA_8888
            flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
            wlp.gravity = Gravity.TOP or Gravity.LEFT
            //默认左边居中
            wlp.x = 0
            wlp.y = DensityUtils.getHeigthAndWidth(activity)[1] / 2
            width = WindowManager.LayoutParams.WRAP_CONTENT
            height = WindowManager.LayoutParams.WRAP_CONTENT
        }
    }

    private fun createView() {
        rootLinearLayout = LinearLayout(activity)
        rootLinearLayout.layoutParams = ViewGroup.LayoutParams(DensityUtils.dip2px(activity, 48f), DensityUtils.dip2px(activity, 48f))

        frameLayout = FrameLayout(activity)
        frameLayout.layoutParams = ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)

        ballView = ImageView(activity)
        ballView.apply {
            layoutParams = ViewGroup.LayoutParams(DensityUtils.dip2px(activity, 48f), DensityUtils.dip2px(activity, 48f))
            callback.onUpdateBallView(ballView, isLeftLocation, false)
            scaleType = ImageView.ScaleType.FIT_XY
            //TODO onClickListener ?
            setOnTouchListener(this@FloatBall)
            frameLayout.addView(this)
        }

        ballMenu = FloatBallMenu(activity, object : FloatBallMenu.FloatingBallMenuCallback {
            override fun onInitMenuData(): MutableList<FloatBallMenu.FloatBallMenuItem> {
                mSize = callback.onInitMenuData().size
                return callback.onInitMenuData()
            }

            override fun onDismissMenu() {
                callback.onDismissMenu(this@FloatBall)
            }

            override fun onMenuItemClick(item: FloatBallMenu.FloatBallMenuItem, pos: Int) {
                callback.onMenuItemClick(this@FloatBall, item, pos)
                menu.dismiss()
            }
        })

        menu = PopupWindow(activity)
        menu.apply {
            contentView = ballMenu.contentView
            width = DensityUtils.dip2px(activity, 48f + mSize * 48f)
            height = DensityUtils.dip2px(activity, 48f)
            isFocusable = true
            setBackgroundDrawable(ColorDrawable())
            isOutsideTouchable = true
            setOnDismissListener {
                hasShowContent = false
                invokeDisplayTimerWork()
            }
        }

        if (isLandscape) {
            handleFullScreenModel()
        }
        rootLinearLayout.addView(frameLayout)
    }

    fun dismissMenu() {
        hasShowContent = false
        menu.dismiss()
        callback.onUpdateBallView(ballView, isLeftLocation, false)
    }

    private fun invokeBallFullOrHalt(isHalf: Boolean) {
        if (hasShowContent && !isHide) {
            return
        }
        this.isHide = isHalf
        if (isHalf) {
            rootLinearLayout.layoutParams = LayoutParams(DensityUtils.dip2px(activity, 24f), DensityUtils.dip2px(activity, 48f))
            layoutParams = LayoutParams(DensityUtils.dip2px(activity, 24f), DensityUtils.dip2px(activity, 48f))
            frameLayout.updateViewLayout(ballView, layoutParams)
        } else {
            rootLinearLayout.layoutParams = LayoutParams(DensityUtils.dip2px(activity, 48f), DensityUtils.dip2px(activity, 48f))
            layoutParams = LayoutParams(DensityUtils.dip2px(activity, 48f), DensityUtils.dip2px(activity, 48f))
            frameLayout.updateViewLayout(ballView, layoutParams)
        }
    }

    private fun invokeMenuShowOrDismiss() {
        if (hasShowContent) {
            hasShowContent = false
            menu.dismiss()
        } else {
            hasShowContent = true
            ballMenu.updateLayout(isLeftLocation)
            if (hasStatusBar) {
                menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
            } else {
                when {
                    isNotch() -> {
                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
                    }
                    isDisplayCutout(activity) -> {
                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y + getStatusBarHeight(activity))
                    }
                    else -> {
                        menu.showAtLocation(ballMenu.contentView, Gravity.NO_GRAVITY, wlp.x + 10, wlp.y)
                    }
                }
            }
        }
    }

    private fun invokeDisplayTimerWork() {
        displayWorker?.invokeAtFixedRate({
            timerHandler.sendEmptyMessage(1000)
        }, 10, 10, TimeUnit.SECONDS)
    }


    fun attach() {
        if (visibility == View.GONE) {
            invokeDisplayTimerWork()
            ballView.visibility = View.VISIBLE
            frameLayout.visibility = View.VISIBLE
            rootLinearLayout.visibility = View.VISIBLE
            visibility = View.VISIBLE
        }
    }

    fun detach() {
        if (visibility == View.VISIBLE) {
            if (hasShowContent) {
                hasShowContent = false
                menu.dismiss()
            }

            displayWorker?.cancel()
            ballView.visibility = View.GONE
            frameLayout.visibility = View.GONE
            rootLinearLayout.visibility = View.GONE
            visibility = View.GONE
        }
    }

    fun release() {
        displayWorker?.apply {
            cancel()
            displayWorker = null
        }
        frameLayout.removeAllViews()
        rootLinearLayout.removeAllViews()
        removeAllViews()
        wm.removeView(this)
    }

    /**
     * 解决PopupWindow无法在状态栏上显示
     *
     */
    private fun handleFullScreenModel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
            try {
                val mLayoutInScreen = PopupWindow::class.java.getDeclaredField("mLayoutInScreen")
                mLayoutInScreen.isAccessible = true
                mLayoutInScreen.set(menu, true)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    private fun getStatusBarHeight(context: Context): Int {
        val id = context.resources.getIdentifier("status_bar_height", "dimen", "android")
        return context.resources.getDimensionPixelSize(id)
    }

    /**
     * 适配小米Android O设备 判断是否是刘海屏
     */
    private fun isNotch(): Boolean {
        try {
            val method = Class.forName("android.os.SystemProperties").getMethod("getInt", String::class.java, Int::class.java)
            return (method.invoke(null, "ro.miui.notch", 0) as Int == 1)
        } catch (e: Exception) {
            e.printStackTrace()
        }
        return false
    }

    /**
     * 判断是否为挖孔屏幕
     */
    private fun isDisplayCutout(activity: Activity): Boolean {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            try {
                return activity.window.decorView.rootWindowInsets?.displayCutout != null
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
        return false
    }


    override fun onTouch(v: View, event: MotionEvent): Boolean {
        displayWorker?.cancel()
        //获取相对屏幕的坐标
        val x = event.rawX
        val y = event.rawY
        //下面的这些事件，跟图标的移动无关，为了区分开拖动和点击事件
        when (event.action) {
            MotionEvent.ACTION_DOWN -> {
                isMove = false
                mTouchStartX = event.x
                mTouchStartY = event.y
            }
            MotionEvent.ACTION_MOVE -> {
                //图标移动的逻辑在这里
                val moveStartX = event.x
                val moveStartY = event.y
                //移动量大于3才判定移动
                if (abs(mTouchStartX - moveStartX) > 3 && abs(mTouchStartY - moveStartY) > 3) {
                    wlp.x = (x - mTouchStartX).toInt()
                    wlp.y = (y - mTouchStartY).toInt()
                    //移动时收起菜单
                    wm.updateViewLayout(this, wlp)
                    isMove = true
                    if (menu.isShowing) {
                        menu.dismiss()
                        hasShowContent = false
                    }
                    return false
                }
            }

            MotionEvent.ACTION_UP -> {
                //大于屏幕宽度的一半吸附在左边
                v.performClick()
                if (wlp.x <= DensityUtils.getHeigthAndWidth(activity)[0] / 2) {
                    wlp.x = 0
                    isLeftLocation = true
                } else {
                    wlp.x = DensityUtils.getHeigthAndWidth(activity)[0]
                    isLeftLocation = false
                }
                wm.updateViewLayout(this, wlp)

                if (isMove) {
                    invokeDisplayTimerWork()
                } else {
                    invokeMenuShowOrDismiss()
                }
                //还原贴边的悬浮球
                invokeBallFullOrHalt(false)
                callback.onUpdateBallView(ballView, isLeftLocation, false)
            }
        }

        return true

    }

    interface FloatBallCallback {

        fun onUpdateBallView(ballView: ImageView, isLeftLocation: Boolean, isHide: Boolean)

        fun onInitMenuData(): MutableList<FloatBallMenu.FloatBallMenuItem>

        fun onMenuItemClick(ball: FloatBall, item: FloatBallMenu.FloatBallMenuItem, pos: Int)

        fun onDismissMenu(ball: FloatBall)
    }


}