package com.qimai.android.widgetlib.popup

import android.graphics.Color
import android.graphics.Point
import android.graphics.drawable.ColorDrawable
import android.os.Build
import android.view.Gravity
import android.view.MotionEvent
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.PopupWindow
import androidx.annotation.IntDef
import androidx.core.view.ViewCompat
import com.qimai.android.tools.getScreenHeight
import com.qimai.android.widgetlib.R

/**
 *   created by wangwei   ON 2019-08-29  email:wangwei_5521@163.com
 *   @version 1.1.1
 *   @Description
 **/
@Suppress("unused")
class QmToolTip private constructor(
    var attachedView: View?,
    var defaultOverlayStyle: Int,
    var gravity: Int
) {

    private val mWindow = PopupWindow()
    private val attachedViewLocation = IntArray(2)

    /**
     * 箭头离 anchor的距离
     */
    private val arrowOffsetOfAnchor = 20

    /**
     *  弹框边框离屏幕的距离
     *   只有Tip 超过 最大高度和宽度的时候才会使用
     */
    private val tipFrameOffsetOfScreenFrame = 20

    private val containerPaddingBig = 30

    private val containerPaddingSmall = 10
    private var containerMeasureWidth = 0
    private var containerMeasureHeight = 0
    private var arrowWeight = 0f

    private var offset = 0

    private constructor(builder: Builder) : this(
        builder.attachedView,
        builder.defaultOverlayStyle,
        builder.gravity
    ) {
        checkMustParams(builder)
        offset = builder.offset
        arrowWeight = builder.arrowWeight
        mWindow.width = ViewGroup.LayoutParams.WRAP_CONTENT
        mWindow.height = ViewGroup.LayoutParams.WRAP_CONTENT

        mWindow.isTouchable = true
        mWindow.isFocusable = true
        mWindow.isOutsideTouchable = true
        gravity = builder.gravity
        val container = FrameLayout(builder.contentView!!.context)
        if (builder.showArrow) {
            when (builder.gravity) {
                Gravity.TOP -> {
                    container.setPadding(
                        containerPaddingSmall,
                        containerPaddingSmall,
                        containerPaddingSmall,
                        containerPaddingBig
                    )
                }
                Gravity.BOTTOM -> {
                    container.setPadding(
                        containerPaddingSmall,
                        containerPaddingBig,
                        containerPaddingSmall,
                        containerPaddingSmall
                    )
                }
            }
        } else {
            container.setPadding(
                containerPaddingSmall,
                containerPaddingSmall,
                containerPaddingSmall,
                containerPaddingSmall
            )
        }
        container.addView(
            builder.contentView,
            ViewGroup.LayoutParams.WRAP_CONTENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )

        container.measure(View.MeasureSpec.UNSPECIFIED, View.MeasureSpec.UNSPECIFIED)

        containerMeasureWidth = container.measuredWidth
        containerMeasureHeight = container.measuredHeight

        builder.attachedView?.getLocationOnScreen(attachedViewLocation)

        when (gravity) {
            Gravity.TOP -> {
                if (containerMeasureHeight > attachedViewLocation[1]) {
                    // view的上边放不下了

                    val containerParams = container.layoutParams
                    if (containerParams == null) {
                        container.layoutParams = ViewGroup.LayoutParams(
                            ViewGroup.LayoutParams.WRAP_CONTENT,
                            ViewGroup.LayoutParams.WRAP_CONTENT
                        )
                    }
                    containerParams.height = attachedViewLocation[1] - 2 * arrowOffsetOfAnchor
                    container.layoutParams = containerParams
                }
            }
            Gravity.BOTTOM -> {
                val remainOffset =
                    getScreenHeight(attachedView!!.context) - attachedViewLocation[1] - builder.attachedView!!.measuredHeight

                if (containerMeasureHeight > remainOffset) {
                    // view的下边放不下了
                    val containerParams = container.layoutParams
                    if (containerParams == null) {
                        container.layoutParams = ViewGroup.LayoutParams(
                            ViewGroup.LayoutParams.WRAP_CONTENT,
                            ViewGroup.LayoutParams.WRAP_CONTENT
                        )
                    }
                    containerParams.height = remainOffset - 2 * arrowOffsetOfAnchor
                    container.layoutParams = containerParams
                }


            }
        }
        container.background = QmTipOverlayDrawable(
            QmTipOverlayDrawable.Builder()
                .withContext(builder.contentView!!.context)
                .withGravity(if(builder.gravity == Gravity.TOP)Gravity.BOTTOM else Gravity.TOP )
                .withOffset(builder.offset)
                .withArrowShow(builder.showArrow)
                .withDefaultOverlayStyle(builder.defaultOverlayStyle)
                .withArrowWeight(builder.arrowWeight)

        )

        mWindow.contentView = container
        mWindow.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))

        mWindow.setTouchInterceptor(View.OnTouchListener { _, event ->
            if (event.action == MotionEvent.ACTION_OUTSIDE) {
                mWindow.dismiss()
                return@OnTouchListener false
            }
            false
        })

        mWindow.setOnDismissListener {
            if (builder.dismissListener != null) {
                builder.dismissListener?.invoke(mWindow)
            }
        }

        builder.attachedView?.addOnAttachStateChangeListener(object :
            View.OnAttachStateChangeListener {
            override fun onViewAttachedToWindow(v: View) {

            }

            override fun onViewDetachedFromWindow(v: View) {
                if (hasShowing()) {
                    dismiss()
                }
            }
        })

        if (builder.animationStyle != -1) {
            mWindow.animationStyle = builder.animationStyle
        }

    }

    fun hasShowing(): Boolean {
        return mWindow.isShowing
    }

    fun dismiss() {
        mWindow.dismiss()
    }


    fun show() {
        if (attachedView != null && !ViewCompat.isAttachedToWindow(attachedView!!)) {
            return
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {
            mWindow.isAttachedInDecor = false
        }
        val point = calculateLocation(attachedView!!)
        // showAsDropDown anchorView 的左下角 为原点  偏移 x, y
        mWindow.showAtLocation(attachedView, Gravity.NO_GRAVITY, point.x, point.y)

    }

    private fun checkMustParams(builder: Builder) {

        checkNotNull(builder.attachedView) {
            "attachedView must not to be null "
        }
    }

    private fun calculateLocation(anchorView: View): Point {
        anchorView.getLocationOnScreen(attachedViewLocation)
        var point = Point()
        when (gravity) {

            Gravity.TOP -> {
                point = calculateTopOffset(anchorView)
            }
            Gravity.BOTTOM -> {
                point = calculateBottomOffset(anchorView)
            }
        }
        return Point(point.x, point.y + offset)
    }

    private fun calculateTopOffset(anchorView: View): Point {

        val point = Point()
        point.x =
            (attachedViewLocation[0] + anchorView.measuredWidth / 2) - containerMeasureWidth / 2
        point.y = attachedViewLocation[1] - containerMeasureHeight

        return point
    }


    private fun calculateBottomOffset(anchorView: View): Point {

        val point = Point()
        point.x =
            (attachedViewLocation[0] + anchorView.measuredWidth / 2 - containerMeasureWidth * arrowWeight).toInt()
        point.y = attachedViewLocation[1] + anchorView.measuredHeight
        return point
    }


    class Builder {

        @IntDef(Gravity.TOP, Gravity.BOTTOM, Gravity.NO_GRAVITY)
        @Retention(AnnotationRetention.SOURCE)
        internal annotation class GravityRange

        internal var attachedView: View? = null
        internal var defaultOverlayStyle: Int = R.style.QmToolTipOverlayDefault

        @GravityRange
        internal var gravity = Gravity.NO_GRAVITY

        internal var contentView: View? = null

        internal var animationStyle: Int = -1

        internal var dismissListener: ((window: PopupWindow) -> Unit)? = null

        internal var showArrow = true

        internal var arrowWeight = 0.5f

        internal var offset = 0


        fun withAttachedView(attachedView: View?) = apply {

            this.attachedView = attachedView
        }

        fun withArrowWeight(arrowWeight: Float) = apply {
            this.arrowWeight = arrowWeight
        }

        fun withDismissListener(listener: (window: PopupWindow) -> Unit) = apply {
            this.dismissListener = listener
        }


        fun withGravity(@GravityRange gravity: Int) = apply {
            this.gravity = gravity
        }

        fun withArrowShow(showArrow: Boolean) = apply {
            this.showArrow = showArrow
        }

        fun withAnimationStyle(animationStyle: Int) = apply {

            this.animationStyle = animationStyle
        }

        fun withDefaultOverlayStyle(defaultOverlayStyle: Int) = apply {

            this.defaultOverlayStyle = defaultOverlayStyle
        }

        fun withContentView(contentView: View) = apply {
            this.contentView = contentView
        }

        fun withOffset(offset: Int) = apply {
            this.offset = offset
        }

        fun build(): QmToolTip {
            return QmToolTip(this)
        }


    }
}