package com.pan_american.android.ui.picture_preview

import android.annotation.SuppressLint
import android.graphics.Matrix
import android.graphics.PointF
import android.graphics.RectF
import android.os.Bundle
import android.view.GestureDetector
import android.view.GestureDetector.OnDoubleTapListener
import android.view.MotionEvent
import android.view.ViewTreeObserver
import android.widget.ImageView
import androidx.appcompat.widget.AppCompatImageView
import com.pan_american.android.OASystem
import com.pan_american.android.R
import com.pan_american.android.base.BaseActivity
import com.pan_american.android.databinding.ActivityPicturePreviewBinding
import com.pan_american.android.databinding.LayoutTitleBinding
import com.squareup.picasso.Callback
import com.squareup.picasso.Picasso
import kotlin.math.atan2
import kotlin.math.sqrt

class PicturePreviewActivity : BaseActivity<ActivityPicturePreviewBinding>() {

    companion object {
        const val NONE = 0
        const val DRAG = 1
        const val ZOOM = 2
    }

    private var fromServer = false

    private var uri = ""

    private var url = ""

    private var picName = ""

    private lateinit var imageView: AppCompatImageView

    private lateinit var gestureDetector: GestureDetector

    private val pointF = PointF()

    private val matrix = Matrix()

    private val tempMatrix = Matrix()

    private val savedMatrix = Matrix()

    //双击放大还是缩小
    private var isZoomIn = false

    private var mode = 0

    private var xDown = 0F

    private var yDown = 0F

    private var oldDist = 0F

    private var oldRotation = 0F

    private var rotation = 0F //旋转角度差值

    private var newRotation = 0F

    private var resetScale = 1F

    private var currScale = 1F

    private var widthScreen = 0

    private var heightScreen = 0

    private var isCheckTopAndBottom = false

    private var isCheckRightAndLeft = false

    private lateinit var titleBinding: LayoutTitleBinding

    override fun getViewBinding() = ActivityPicturePreviewBinding.inflate(layoutInflater)

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        intent.apply {

            fromServer = getBooleanExtra("fromServer", false)
            picName = getStringExtra("name").toString()

            if (fromServer) {
                url = getStringExtra("url").toString()
            } else {
                uri = getStringExtra("uri").toString()
            }

        }

        imageView = binding.imageView

        initTitle()
        initViews()
        initEvents()
    }

    override fun initTitle() {
        titleBinding = LayoutTitleBinding.bind(binding.root).apply {
            titleText.text = resources.getString(R.string.picture_preview)

            backButton.setOnClickListener {
                back()
            }
        }
    }

    @SuppressLint("ClickableViewAccessibility")
    override fun initViews() {

//        binding.imageName.text = picName

        imageView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
            override fun onGlobalLayout() {
                imageView.viewTreeObserver.removeOnGlobalLayoutListener(this)

                //获取imageView的宽和高
                // 此时可以安全地获取ImageView的尺寸并设置图片
                widthScreen = imageView.width
                heightScreen = imageView.height

                if (fromServer) {
                    Picasso.get().load(url).resize(widthScreen, heightScreen).centerInside().into(imageView, object : Callback {
                        override fun onSuccess() {

                            imageView.scaleType = ImageView.ScaleType.MATRIX

                            //初始化图片的矩阵
                            matrix.set(imageView.imageMatrix)

                            /**
                             * 初始化 将图片放在屏幕中心位置
                             */
                            center()

                            /**
                             * 图片设置中心之后，重新设置图片的缩放矩阵
                             */
                            imageView.imageMatrix = matrix
                        }

                        override fun onError(p0: Exception?) {
                            showErrorInfo(R.string.picture_load_error)
                        }
                    })
                } else {
                    Picasso.get().load(uri).resize(widthScreen, heightScreen).centerInside().into(imageView, object : Callback {
                        override fun onSuccess() {
                            imageView.scaleType = ImageView.ScaleType.MATRIX

                            //初始化图片的矩阵
                            matrix.set(imageView.imageMatrix)

                            /**
                             * 初始化 将图片放在屏幕中心位置
                             */
                            center()

                            /**
                             * 图片设置中心之后，重新设置图片的缩放矩阵
                             */
                            imageView.imageMatrix = matrix
                        }

                        override fun onError(p0: java.lang.Exception?) {

                        }
                    })
                }
            }
        })

    }

    @SuppressLint("ClickableViewAccessibility")
    override fun initEvents() {

        /**
         * 设置ImageView的触摸事件
         */
        imageView.setOnTouchListener { _, event ->
            onTouchEvent(event)
            true
        }

        /**
         * 初始化手势
         * 单击  双击 长按
         * 这三个均是手势起作用
         * 如果想要在这三种手势中进行何种操作，
         * 将代码放在对应的方法中即可。
         */
        gestureDetector = GestureDetector(OASystem.context, object : GestureDetector.SimpleOnGestureListener() {})

        gestureDetector.setOnDoubleTapListener(object : OnDoubleTapListener {

            /**
             * 单击手势 会触发该方法一次
             * 单击对应的代码应放在这里
             */
            override fun onSingleTapConfirmed(p0: MotionEvent): Boolean {

//                this@PicturePreviewActivity.finish()
                return false
            }

            /**
             * 双击手势的时候 会触发该方法一次
             * 所以双击手势对应的代码应放在这里
             */
            override fun onDoubleTap(motionEvent: MotionEvent): Boolean {

//                pointF.x = motionEvent.x
//                pointF.y = motionEvent.y
//                tempMatrix.set(savedMatrix)
//
//                if (resetScale < 1F) {
//                    isZoomIn = true
//                }
//
//                isZoomIn = if (isZoomIn) {
//                    tempMatrix.postScale(resetScale, resetScale, pointF.x, pointF.y)
//                    false
//                } else {
//                    true
//                }
//
//                matrix.set(tempMatrix)
//                center()
//                imageView.imageMatrix = matrix

                return false
            }

            override fun onDoubleTapEvent(p0: MotionEvent): Boolean {

                return false
            }
        })
    }

    override fun onTouchEvent(event: MotionEvent): Boolean {
        /**
         * 在这里调用手势的方法
         * 这是手势和触摸事件同时使用的方法
         */
        if (gestureDetector.onTouchEvent(event)) {
            return true
        } else {

            when (event.action and MotionEvent.ACTION_MASK) {

                MotionEvent.ACTION_DOWN -> {

                    mode = DRAG

                    xDown = event.x
                    yDown = event.y

                    /**
                     * 单个手指放下，首先保存图片的缩放矩阵到savedMatrix
                     */
                    savedMatrix.set(matrix)
                }

                MotionEvent.ACTION_POINTER_DOWN -> {

                    mode = ZOOM

                    /**
                     * 第二个手指刚放下时
                     * 计算两个手指间的距离
                     */
                    oldDist = spacing(event)

                    /**
                     * 第二个手指刚放下时
                     * 计算两个手指间的旋转角度
                     */
                    oldRotation = rotation(event)
                    savedMatrix.set(matrix)
                    /**
                     * 第二个手指刚放下时
                     * 计算两个手指见的中间点坐标，并存在pointF中
                     */
                    midPoint(pointF, event)

                }

                MotionEvent.ACTION_MOVE -> {

                    if (mode == ZOOM) {

                        tempMatrix.set(savedMatrix)

                        /**
                         * 两个手指开始移动
                         * 计算移动后旋转角度
                         */
                        newRotation = rotation(event)

                        /**
                         * 两个角度之差
                         * 即是图片的旋转角度
                         */
                        rotation = newRotation - oldRotation

                        /**
                         * 计算移动后两点间的中间点
                         */
                        val newDist = spacing(event)

                        /**
                         * 两个中间点的商即时放大倍数
                         */
                        val scale = newDist / oldDist

                        /**
                         * 放大倍数的倒数即是还原图片原来大小的倍数
                         */
                        resetScale = oldDist / newDist

                        tempMatrix.postScale(scale, scale, pointF.x, pointF.y)// 縮放
//                        tempMatrix.postRotate(rotation, pointF.x, pointF.y)// 旋轉

                        matrix.set(tempMatrix)

                        /**
                         * 调用该方法即可重新图片
                         */
                        imageView.imageMatrix = matrix

                    } else if (mode == DRAG) {

                        tempMatrix.set(savedMatrix)

                        var tx = event.x - xDown
                        var ty = event.y - yDown

                        /**
                         * 单个手指移动后的距离大于20 才算作移动
                         */
                        if (sqrt(tx * tx + ty * ty) > 20F) {

                            /**
                             * 设置图片宽高与屏幕宽高的大小的boolean类型的值
                             */

                            /**
                             * 得到目前图片的宽高
                             */
                            val rectF = getMatrixRectF()

                            /**
                             * 图片宽度小于屏幕大小
                             * 不移动
                             */
                            if (rectF.width() <= widthScreen) {
                                tx = 0F
                                isCheckRightAndLeft = false
                            } else {
                                isCheckRightAndLeft = true
                            }

                            /**
                             * 图片高度小于屏幕高度
                             * 不移动
                             */
                            if (rectF.height() <= heightScreen) {
                                ty = 0F
                                isCheckTopAndBottom = false
                            } else {
                                isCheckTopAndBottom = true
                            }

                            tempMatrix.postTranslate(tx, ty)// 平移

                            /**
                             * 如果想在拖动图片的同时检测图片边缘是否
                             * 到达屏幕的边缘，则取消下面的注释
                             */
//                            checkDxDyBounds()
                            matrix.set(tempMatrix)
                            imageView.imageMatrix = matrix
                        }
                    }
                }

                MotionEvent.ACTION_UP -> {

                }

                MotionEvent.ACTION_POINTER_UP -> {

                    if (mode == ZOOM) {

                        /**
                         * 双手放开，停止图片的旋转和缩放
                         * Reset_scale还原图片的缩放比例
                         */
//                        val rectF = getMatrixRectF()
//
//                        if (rectF.width() < widthScreen || rectF.height() < heightScreen) {
//
//                            val imageRatio = rectF.width() / rectF.height()
//
//                            tempMatrix.postScale(widthScreen / rectF.width(), heightScreen / rectF.height() * imageRatio, pointF.x, pointF.y)
//                        }
//                        tempMatrix.postScale(resetScale, resetScale, pointF.x, pointF.y)

                        /**
                         * 双手放开，停止缩放、旋转图片，此时根据已旋转的角度
                         * 计算还原图片的角度，最终的效果是把图片竖直或横平方正。
                         */
                        setRotate()
                        matrix.set(tempMatrix)

                        /**
                         * 将图片放在屏幕中间位置
                         */
//                        center()

                        imageView.imageMatrix = matrix
                        tempMatrix.reset()

                    } else if (mode == DRAG) {
                        
                        /**
                         * 单手拖动图片，放开手指，停止拖动
                         * 此时检测图片是否已经偏离屏幕边缘
                         * 如果偏离屏幕边缘，则图片回弹
                         */

//                        checkDxDyBounds()

                        matrix.set(tempMatrix)
                        imageView.imageMatrix = matrix
                        tempMatrix.reset()
                    }

                    mode = NONE

                }
            }

            return true
        }
    }

    /**
     * 根据当前图片的Matrix获得图片的范围
     * 这里获取的是当前显示的图片的大小。
     * 图片放大后，获取的就是图片放大后的图片的大小。
     * 图片缩小后，获取的就是图片缩小后的图片的大小。
     *
     * 这个大小与图片的大小是有区别的。
     * 下面是固定用法，记住即可。
     * @return
     */
    private fun getMatrixRectF(): RectF {
        val m = matrix
        val rect = RectF()
        val drawable = imageView.drawable

        if (drawable != null) {

            rect.set(0F, 0F, drawable.intrinsicWidth.toFloat(), drawable.intrinsicHeight.toFloat())
            m.mapRect(rect)
        }

        return rect
    }

    /**
     * 横向、纵向 图片居中
     */
    private fun center() {
        val rect = getMatrixRectF()
        var deltaX = 0F
        var deltaY = 0F
        val height = rect.height()
        val width = rect.width()

        /**
         *  图片小于屏幕大小，则居中显示。
         *  大于屏幕，如果图片上方留空则往上移，
         *  图片下方留空则往下移
         */
        val screenHeight = heightScreen
        if (height < screenHeight) {

            deltaY = (screenHeight - height) / 2 - rect.top

        } else if (rect.top > 0) {

            deltaY = -rect.top

        } else if (rect.bottom < screenHeight) {

            deltaY = imageView.height - rect.bottom

        }

        val screenWidth = widthScreen
        if (width < screenWidth) {

            deltaX = screenWidth - width / 2 - rect.left

        } else if (rect.left > 0) {

            deltaX = -rect.left

        } else if (rect.right < screenWidth) {

            deltaX = screenWidth - rect.right

        }
        
        matrix.postTranslate(deltaX, deltaY)
    }

    // 触碰两点间距离
    private fun spacing(event: MotionEvent ): Float {
        val x = event.getX(0) - event.getX(1)
        val y = event.getY(0) - event.getY(1)
        return  sqrt(x * x + y * y)
    }

    // 取手势中心点
    private fun midPoint(point: PointF, event: MotionEvent) {
        val x = event.getX(0) + event.getX(1)
        val y = event.getY(0) + event.getY(1)
        point.set(x / 2, y / 2)
    }

    // 取旋转角度
    private fun rotation(event: MotionEvent): Float {
        val deltaX = (event.getX(0) - event.getX(1))
        val deltaY = (event.getY(0) - event.getY(1))
        /**
         * 反正切函数
         * 计算两个坐标点的正切角度
         */
        val radians = atan2(deltaY, deltaX).toDouble()
        return Math.toDegrees(radians).toFloat()
    }
    /**
     * 手指松开，确定旋转的角度
     */
    private fun setRotate(){

        when(rotation) {
            in -135F .. -90F -> {
                tempMatrix.postRotate(-90F, pointF.x, pointF.y)
            }

            in -90F..-45F -> {
            tempMatrix.postRotate(-90F, pointF.x, pointF.y)
            }

            in -45F.. 0F -> {
                tempMatrix.postRotate(0F, pointF.x, pointF.y)
            }

            in 0F .. 45F -> {
                tempMatrix.postRotate(0F, pointF.x, pointF.y)
            }

            in 45F .. 90F -> {
                tempMatrix.postRotate(90F, pointF.x, pointF.y)
            }

            in 90F .. 135F -> {
                tempMatrix.postRotate(90F, pointF.x, pointF.y)
            }
        }
    }
    /**
     * 检测图片偏离屏幕两边的距离
     * 然后平移，是图片边缘在屏幕边，
     * 使图片周围没有空白
     */
    private fun checkDxDyBounds(){
        val rectF = getMatrixRectF()
        var dx = 0.0F
        var dy = 0.0F
        /**
         * 如果图片的左侧大于零，说明图片左侧向右
         * 偏离了左侧屏幕，则左移偏离的距离.
         * rectF.left的值，是基于左侧坐标计算的。
         * 图片正常情况下，该值为0.
         * 当图片向右侧拖动以后，该值大于0.
         * 当图片向左侧拖动以后，该值小于0.
         */
        if (rectF.left > 0) {
            dx = -rectF.left
        }
        /**
         * 如果图片的右侧偏离屏幕的右侧，则
         * 图片右移图片的宽度与图片显示的宽度的差.
         *
         * rectF.right的值，是基于左侧计算的，图片没有缩放旋转情况下，
         * 该值==touchImageView.getWidth()图片的宽度。
         * 当拖动图片以后，该值变化，等于显示的图片的宽度
         */
        if (rectF.right < 0) {
            dx = widthScreen - rectF.right
        }
        /**
         * 当图片顶部大于0，说明图片向下偏离屏幕顶部，
         * 则图片向上回弹偏离的距离。
         *
         * rectF.top的值基于顶部坐标，
         * 图片正常情况下，该值=0.
         */
        if (rectF.top > 0) {
            dy = -rectF.top
        }
        /**
         * 当图片底部小于图片高度时，图片偏离屏幕底部
         * 则图片回弹图片的高度与显示的图片的高度之差。
         *
         * rectF.bottom的值，基于顶部坐标。
         * 图片正常情况下，该值=图片的高度。
         */
        if (rectF.bottom < 0) {
            dy = heightScreen - rectF.bottom
        }
        /**
         * 计算后，设置图片回弹
         */
        tempMatrix.postTranslate(dx, dy)
    }
}