package com.gh.gamecenter

import android.animation.Animator
import android.animation.AnimatorSet
import android.animation.ObjectAnimator
import android.animation.ValueAnimator
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Dialog
import android.content.Context
import android.content.Intent
import android.graphics.BitmapFactory
import android.graphics.Color
import android.graphics.PointF
import android.net.Uri
import android.os.Bundle
import android.text.TextUtils
import android.util.Base64
import android.util.SparseArray
import android.view.View
import android.view.ViewGroup
import android.view.ViewTreeObserver.OnGlobalLayoutListener
import android.view.Window
import android.view.animation.DecelerateInterpolator
import android.widget.ImageView
import android.widget.LinearLayout
import android.widget.RelativeLayout
import android.widget.TextView
import androidx.core.content.ContextCompat
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.LifecycleEventObserver
import androidx.lifecycle.LifecycleOwner
import androidx.transition.*
import androidx.viewpager.widget.PagerAdapter
import androidx.viewpager.widget.ViewPager
import androidx.viewpager.widget.ViewPager.OnPageChangeListener
import com.davemorrissey.labs.subscaleview.SubsamplingScaleImageView
import com.facebook.drawee.backends.pipeline.Fresco
import com.facebook.imagepipeline.core.ImagePipeline
import com.facebook.imagepipeline.request.ImageRequest
import com.gh.common.constant.Config
import com.gh.gamecenter.common.base.activity.BaseActivity
import com.gh.gamecenter.common.constant.EntranceConsts
import com.gh.gamecenter.common.entity.CommunityEntity
import com.gh.gamecenter.common.retrofit.Response
import com.gh.gamecenter.common.utils.*
import com.gh.gamecenter.common.utils.ImageUtils.getTransformedUrl
import com.gh.gamecenter.common.view.DraggableBigImageView
import com.gh.gamecenter.common.view.Gh_RelativeLayout
import com.gh.gamecenter.core.runOnIoThread
import com.gh.gamecenter.core.utils.*
import com.gh.gamecenter.databinding.ActivityViewimageBinding
import com.gh.gamecenter.entity.ImageInfoEntity
import com.gh.gamecenter.feature.entity.AnswerEntity
import com.gh.gamecenter.qa.article.detail.ArticleDetailActivity
import com.gh.gamecenter.retrofit.RetrofitManager
import com.github.piasy.biv.view.BigImageView
import com.github.piasy.biv.view.FrescoImageViewFactory
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.schedulers.Schedulers
import java.io.BufferedOutputStream
import java.io.File
import java.io.FileOutputStream
import java.util.*
import kotlin.math.abs
import kotlin.math.roundToInt

/**
 * 查看游戏截图页面
 *
 * @author 黄壮华
 *
 */
class ImageViewerActivity : BaseActivity(), OnPageChangeListener {

    private var mScale = 0F
    private var mAnimating = false
    private var mImageRatio = 1F
    private var mViewRatio = 1F
    lateinit var mViewPager: ViewPager
    lateinit var mProgressHint: TextView
    lateinit var mIndicatorMask: View
    lateinit var mIndicatorTv: TextView
    lateinit var mBackgroundView: View
    lateinit var mSavePicBtn: View
    lateinit var mArticleDetailBtn: View

    private lateinit var mBinding: ActivityViewimageBinding
    private var adapter: ViewImageAdapter? = null
    private var mImagePipeline: ImagePipeline? = null
    private var mShowBase64Image = false
    private var mUrlList: ArrayList<String>? = null
    private var mViewedSet: HashSet<Int>? = null // 让调用者知道该图片是否被看过了
    private var mImageInfoMap: MutableMap<String, ImageInfoEntity>? = null
    private var mBigImageView: BigImageView? = null
    private var mContainer: ViewGroup? = null
    private var mContainerMap = SparseArray<ViewGroup>()
    private var mFinalUrl = ""

    private var mInitialPosition = 0
    private var mUseEnterAndExitAnimation = false
    private var mShowSaveBtn = false
    private var mAnswerEntity: AnswerEntity? = null
    private var mIsFromImageContainerView = false

    private var mLimitWidth = 0
    private var mOriginLeftList: ArrayList<Int>? = null
    private var mOriginTopList: ArrayList<Int>? = null
    private var mOriginHeightList: ArrayList<Int>? = null
    private var mOriginWidthList: ArrayList<Int>? = null
    private var mOriginLeft = 0
    private var mOriginTop = 0
    private var mOriginHeight = 0
    private var mOriginWidth = 0
    private var mOriginCenterX = 0
    private var mOriginCenterY = 0
    private var mOriginHeightWidthRatio = 0f
    private var mTargetHeight = 0f
    private var mTargetWidth = 0f
    private var mScaleX = 0f
    private var mScaleY = 0f
    private var mTranslationX = 0f
    private var mTranslationY = 0f
    private var mTargetCenterX = 0f
    private var mTargetCenterY = 0f

    override fun getLayoutId() = R.layout.activity_viewimage

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

        mBinding = ActivityViewimageBinding.bind(mContentView)
        mViewPager = mBinding.imageDetailPage
        mProgressHint = mBinding.imageDetailProgress
        mIndicatorMask = mBinding.imageMask
        mIndicatorTv = mBinding.imageIndicatorTv
        mBackgroundView = mBinding.backgroundView
        mSavePicBtn = mBinding.btnSavePic
        mArticleDetailBtn = mBinding.btnArticleDetail

        mViewedSet = HashSet()
        mImageInfoMap = HashMap()
        mImagePipeline = Fresco.getImagePipeline()

        mInitialPosition = savedInstanceState?.getInt(EntranceConsts.KEY_CURRENTITEM, 0) ?: 0

        intent.extras?.let {
            if (it.getBoolean(KEY_BASE64)) {
                mShowBase64Image = true
                mUrlList = ArrayList()
                mUrlList?.add(base64Image)
            } else {
                mUrlList = it.getStringArrayList(KEY_URL_LIST) ?: arrayListOf()
                mInitialPosition = it.getInt(KEY_CURRENT, 0)
            }
            mShowSaveBtn = it.getBoolean(KEY_SHOW_SAVE)
            mUseEnterAndExitAnimation = it.getBoolean(KEY_USE_ENTER_AND_EXIT_ANIMATION)
            mAnswerEntity = it.getParcelable(AnswerEntity::class.java.name)
            mOriginLeftList = it.getIntegerArrayList(KEY_LEFT)
            mOriginTopList = it.getIntegerArrayList(KEY_TOP)
            mOriginHeightList = it.getIntegerArrayList(KEY_HEIGHT)
            mOriginWidthList = it.getIntegerArrayList(KEY_WIDTH)
            mIsFromImageContainerView = it.getBoolean(KEY_IS_FROM_IMAGE_CONTAINER_VIEW)
        }

        if (mUrlList == null || mUrlList?.isEmpty() == true) {
            ToastUtils.toast("无法查看大图")
            finish()
        }

        mSavePicBtn.visibleIf(mShowSaveBtn)
        mArticleDetailBtn.visibleIf(mAnswerEntity != null)
        mIndicatorMask.goneIf(mUrlList?.size == 1)
        mIndicatorTv.text = String.format("%d/%d", mInitialPosition + 1, mUrlList!!.size)

        // init slide
        val widthPixels = DisplayUtils.getScreenWidth()
        mLimitWidth = if (NetworkUtils.isWifiOr4GConnected(this)) {
            widthPixels * 2
        } else {
            widthPixels
        }
        // init viewPage
        adapter = ViewImageAdapter()
        mViewPager.adapter = adapter
        mViewPager.currentItem = mInitialPosition
        mViewPager.addOnPageChangeListener(this)
        mProgressHint.setOnClickListener {
            val position = mViewPager.currentItem
            val `object`: Any? = mViewPager.findViewWithTag(position)
            if (`object` != null) {
                val view = `object` as RelativeLayout
                val imageView: BigImageView = view.findViewById(R.id.viewimage_iv_show)
                val url = mUrlList!![position]
                imageView.showImage(Uri.parse(url))
                imageView.setImageLoaderCallback(object : SimpleImageLoader() {
                    @SuppressLint("SetTextI18n")
                    override fun onProgress(progress: Int) {
                        if (position == mViewPager.currentItem) { // 防止下载过程中切换图片
                            if (progress < 100) {
                                mProgressHint.text = "$progress%"
                            } else {
                                mProgressHint.text = "已完成"
                                mBaseHandler.postDelayed({
                                    if (position == mViewPager.currentItem) {  // 防止等待过程中切换图片
                                        mProgressHint.visibility = View.GONE
                                    }
                                }, 500)
                            }
                        }
                    }
                })
            }
        }

        mSavePicBtn.setOnClickListener {
            checkStoragePermissionBeforeAction {
                mBigImageView?.currentImageFile?.run {
                    ImageUtils.saveImageToFile(this, mFinalUrl)
                }
            }
        }

        mArticleDetailBtn.setOnClickListener {
            val intent = ArticleDetailActivity.getIntent(
                this,
                CommunityEntity(
                    if (!mAnswerEntity?.communityId.isNullOrEmpty()) mAnswerEntity?.communityId
                        ?: "" else mAnswerEntity?.articleCommunityId ?: "",
                    mAnswerEntity?.communityName ?: ""
                ),
                mAnswerEntity?.id
                    ?: "",
                mEntrance,
                ""
            )
            startActivity(intent)
            finish()
        }

        initEnterAnimation()
        DisplayUtils.transparentStatusAndNavigation(this)
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putInt(EntranceConsts.KEY_CURRENTITEM, mViewPager.currentItem)
    }

    override fun onDestroy() {
        super.onDestroy()
        if (mShowBase64Image) {
            mUrlList?.clear()
            base64Image = ""
        }
        mContainerMap.clear()
    }

    @SuppressLint("SetTextI18n")
    override fun onPageScrolled(
        position: Int, positionOffset: Float,
        positionOffsetPixels: Int
    ) {
        if (positionOffset != 0f) {
            mProgressHint.visibility = View.GONE
        } else {
            val url = mUrlList!![position]
            val imageInfoEntity = mImageInfoMap!![url]
            if (imageInfoEntity?.fileSize != null &&
                !mImagePipeline!!.isInBitmapMemoryCache(ImageRequest.fromUri(url)) &&
                !mImagePipeline!!.isInDiskCacheSync(ImageRequest.fromUri(url))
            ) {
                val size = String.format(
                    Locale.CHINA, "%.1fM",
                    Integer.valueOf(imageInfoEntity.fileSize.value) / 1024f / 1024f
                )
                mProgressHint.visibility = View.VISIBLE
                mProgressHint.text = "查看原图($size)"
                val layoutParams = mProgressHint.layoutParams
                layoutParams.width = ViewGroup.LayoutParams.WRAP_CONTENT
                mProgressHint.layoutParams = layoutParams
            }
        }
        mViewedSet?.add(position)
        setResult(Activity.RESULT_OK, Intent().putExtra(VIEWED_IMAGE, mViewedSet))
    }

    private fun updateOriginPosition(position: Int) {
        if (position >= mOriginLeftList?.size ?: 0 || position >= mOriginTopList?.size ?: 0 || position >= mOriginHeightList?.size ?: 0 || position >= mOriginWidthList?.size ?: 0) return
        mContainer = mContainerMap[position]
        if (mContainer != null) {
            mBigImageView = mContainerMap[position].findViewById(R.id.viewimage_iv_show)
        }
        mOriginLeft = mOriginLeftList?.safelyGetInRelease(position) ?: 0
        mOriginTop = mOriginTopList?.safelyGetInRelease(position) ?: 0
        mOriginHeight = mOriginHeightList?.safelyGetInRelease(position) ?: 0
        mOriginWidth = mOriginWidthList?.safelyGetInRelease(position) ?: 0
        resizeImage(position)
        mOriginCenterX = mOriginLeft + mOriginWidth / 2
        mOriginCenterY = mOriginTop + mOriginHeight / 2
        mOriginHeightWidthRatio = mOriginHeight.toFloat() / mOriginWidth
        mScaleX = mOriginWidth.toFloat() / mTargetWidth
        mScaleY = mScaleX
        mTranslationX = mOriginCenterX - mTargetCenterX
        mTranslationY = mOriginCenterY - mTargetCenterY
    }

    // 处理非等比例缩放的图片
    private fun resizeImage(position: Int) {
        mBigImageView?.ssiv?.run {
            mScale = scale
            mImageRatio = sWidth / sHeight.toFloat()
            mViewRatio = mOriginWidth / mOriginHeight.toFloat()
            if (!shouldResize()) return
            if (mViewRatio < mImageRatio) {
                mOriginWidth = (mOriginHeight * mImageRatio).round2Int()
                mOriginLeft -= (mOriginWidth - (mOriginWidthList?.safelyGetInRelease(position) ?: 0)) / 2
            } else {
                mOriginHeight = (mOriginWidth / mImageRatio).round2Int()
                if (justChangeBoundsAndTransform()) return
                mOriginTop -= (mOriginHeight - (mOriginHeightList?.safelyGetInRelease(position) ?: 0)) / 2
            }
        }
    }

    private fun Float.round2Int() = if (!isNaN()) roundToInt() else 0

    override fun onPageSelected(position: Int) {
        /*var ghRelativeLayout: Gh_RelativeLayout?
        for (i in 0 until mViewPager.childCount) {
            if (mViewPager.getChildAt(i).tag != null) {
                ghRelativeLayout = mViewPager.getChildAt(i) as? Gh_RelativeLayout
                if (ghRelativeLayout == null) {
                    return
                }
                val imageView: BigImageView = ghRelativeLayout.findViewById(R.id.viewimage_iv_show)
                val ssiv = imageView.ssiv
                ssiv?.resetScaleAndCenter()
            }
        }*/
        mIndicatorTv.text = String.format("%d/%d", position + 1, mUrlList!!.size)
    }

    override fun onPageScrollStateChanged(newState: Int) {}

    private fun initEnterAnimation() {
        mViewPager.viewTreeObserver
            .addOnGlobalLayoutListener(object : OnGlobalLayoutListener {
                override fun onGlobalLayout() {
                    mViewPager.viewTreeObserver.removeOnGlobalLayoutListener(this)
                    mOriginLeft = mOriginLeftList?.safelyGetInRelease(mInitialPosition) ?: 0
                    mOriginTop = mOriginTopList?.safelyGetInRelease(mInitialPosition) ?: 0
                    mOriginHeight = mOriginHeightList?.safelyGetInRelease(mInitialPosition) ?: 0
                    mOriginWidth = mOriginWidthList?.safelyGetInRelease(mInitialPosition) ?: 0
                    mOriginCenterX = mOriginLeft + mOriginWidth / 2
                    mOriginCenterY = mOriginTop + mOriginHeight / 2
                    mOriginHeightWidthRatio = mOriginHeight.toFloat() / mOriginWidth
                    val location = IntArray(2)
                    mBigImageView?.getLocationOnScreen(location)
                    mTargetHeight = mBigImageView?.height?.toFloat() ?: 0F
                    mTargetWidth = mBigImageView?.width?.toFloat() ?: 0F
                    mScaleX = if (mOriginWidth == 0 && mTargetWidth == 0F) 1F else mOriginWidth.toFloat() / mTargetWidth
                    mScaleY = mScaleX
                    mTargetCenterX = location[0] + mTargetWidth / 2
                    mTargetCenterY = location[1] + mTargetHeight / 2
                    mTranslationX = mOriginCenterX - mTargetCenterX
                    mTranslationY = mOriginCenterY - mTargetCenterY

                    if (mUseEnterAndExitAnimation) {
                        mBigImageView?.translationX = mTranslationX
                        mBigImageView?.translationY = mTranslationY
                        if (!mScaleX.isNaN() && mScaleX < Float.MAX_VALUE) {
                            mBigImageView?.scaleX = mScaleX
                            mBigImageView?.scaleY = mScaleY
                        }
                    }

                    performEnterAnimation()
                }
            })
    }

    private fun loadImageInfo(position: Int, width: Int) {
        val url = mUrlList!![position]
        RetrofitManager.getInstance()
            .api.getImageInfo("$url?x-oss-process=image/info")
            .subscribeOn(Schedulers.io())
            .observeOn(AndroidSchedulers.mainThread())
            .subscribe(object : Response<ImageInfoEntity?>() {
                override fun onResponse(response: ImageInfoEntity?) {
                    if (response?.imageWidth != null && Integer.valueOf(response.imageWidth.value) > width) {
                        mImageInfoMap!![url] = response
                        if (position == mViewPager.currentItem) {
                            onPageScrolled(position, 0f, 0) // 刷新下载原图提示按钮
                        }
                    }
                }
            })
    }

    private fun loadImage(
        thumbnailUrl: String,
        compressedUrl: String?,
        imageView: BigImageView
    ) {
        if (TextUtils.isEmpty(thumbnailUrl)) return
        if (thumbnailUrl.startsWith("data:image/png;base64")) {
            runOnIoThread {
                val base64String = thumbnailUrl.replace("data:image/png;base64", "")
                try {
                    val imageFile = File(cacheDir.absolutePath + File.separator + System.currentTimeMillis() + ".png")
                    val decodedString = Base64.decode(base64String, Base64.DEFAULT)
                    val bos = BufferedOutputStream(FileOutputStream(imageFile))
                    bos.write(decodedString)
                    bos.flush()
                    bos.close()
                    runOnUiThread {
                        imageView.setImageViewFactory(FrescoImageViewFactory())
                        imageView.showImage(Uri.fromFile(imageFile))
                    }
                } catch (e: Exception) {
                    e.printStackTrace()
                }
            }
        } else {
            // 添加GIF支持
            imageView.setImageViewFactory(FrescoImageViewFactory())
            imageView.setThumbnailScaleType(ImageView.ScaleType.FIT_CENTER)
            imageView.showImage(Uri.parse(thumbnailUrl), Uri.parse(compressedUrl))
        }
    }

    private fun finishWithAnimation(fadeOnly: Boolean) {
        val animatorSet = AnimatorSet()

        val translateXAnimator = ValueAnimator.ofFloat(0F, mTranslationX).apply {
            addUpdateListener { va -> mBigImageView?.x = (va.animatedValue as Float) }
        }
        val translateYAnimator = ValueAnimator.ofFloat(0F, mTranslationY).apply {
            addUpdateListener { va -> mBigImageView?.y = (va.animatedValue as Float) }
        }
        val scaleYAnimator = ValueAnimator.ofFloat(1F, mScaleY).apply {
            addUpdateListener { va ->
                if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
                    mBigImageView?.scaleY = (va.animatedValue as Float)
                }
            }
        }
        val scaleXAnimator = ValueAnimator.ofFloat(1F, mScaleX).apply {
            addUpdateListener { va ->
                if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
                    mBigImageView?.scaleX = (va.animatedValue as Float)
                }
            }
        }
        val backgroundAlphaAnimation = ValueAnimator.ofFloat(1F, 0F).apply {
            addUpdateListener { va -> mBackgroundView.alpha = (va.animatedValue as Float) }
        }
        val alphaAnimator = ValueAnimator.ofFloat(1F, 0F).apply {
            addUpdateListener { va -> mViewPager.alpha = (va.animatedValue as Float) }
        }

        if (mUseEnterAndExitAnimation && !fadeOnly) {
            if (mFinalUrl.contains(".gif") || mUrlList!![mViewPager.currentItem].contains(".gif")) {
                animatorSet.apply {
                    playTogether(
                        translateXAnimator,
                        translateYAnimator,
                        scaleXAnimator,
                        scaleYAnimator,
                        backgroundAlphaAnimation
                    )
                    duration = ANIMATION_DURATION
                    doOnStart { mIndicatorMask.visibility = View.GONE }
                    doOnEnd {
                        it.removeAllListeners()
                        finish()
                        overridePendingTransition(0, 0)
                    }
                }.start()
            } else {
                startEndTransition()
            }
        } else {
            animatorSet.apply {
                playTogether(alphaAnimator, backgroundAlphaAnimation)
                duration = ANIMATION_DURATION
                doOnStart { mIndicatorMask.visibility = View.GONE }
                doOnEnd {
                    it.removeAllListeners()
                    finish()
                    overridePendingTransition(0, 0)
                }
            }.start()
        }
    }

    private fun shouldResize() = abs(mImageRatio - mViewRatio) > RATIO_DIFF

    private fun justChangeBoundsAndTransform() =
        mImageRatio < mViewRatio && mIsFromImageContainerView && adapter?.count == 1

    private fun startEndTransition() {
        if (mAnimating) return
        val doResizeTransition = Runnable {
            TransitionManager.beginDelayedTransition(mContainer as ViewGroup, TransitionSet().apply {
                addTransition(ChangeBounds())
                addTransition(ChangeTransform())
                if (!justChangeBoundsAndTransform()) addTransition(ResizeTransition())
                duration = RESIZE_DURATION
                interpolator = DecelerateInterpolator()
                addListener(object : TransitionListenerAdapter() {
                    override fun onTransitionStart(transition: Transition) {
                        mAnimating = true
                    }

                    override fun onTransitionEnd(transition: Transition) {
                        if (!mAnimating) return
                        mAnimating = false
                        this@ImageViewerActivity.finish()
                        overridePendingTransition(0, 0)
                    }
                })
            })
            mBigImageView?.ssiv?.run {
                layoutParams = layoutParams.apply {
                    if (mViewRatio < mImageRatio) {
                        width = mOriginWidthList?.safelyGetInRelease(mViewPager.currentItem) ?: 0
                    } else {
                        height = mOriginHeightList?.safelyGetInRelease(mViewPager.currentItem) ?: 0
                    }
                    if (this is ViewGroup.MarginLayoutParams) {
                        if (mViewRatio < mImageRatio) {
                            leftMargin = mOriginLeftList?.safelyGetInRelease(mViewPager.currentItem) ?: 0
                        } else {
                            topMargin = mOriginTopList?.safelyGetInRelease(mViewPager.currentItem) ?: 0
                        }
                    }
                }
            }
        }
        val doTransition = Runnable {
            TransitionManager.beginDelayedTransition(mContainer as ViewGroup, TransitionSet().apply {
                addTransition(ChangeBounds())
                addTransition(ChangeTransform())
                addTransition(SsivTransition())
                duration = ANIMATION_DURATION
                interpolator = DecelerateInterpolator()
                addListener(object : TransitionListenerAdapter() {
                    override fun onTransitionStart(transition: Transition) {
                        mAnimating = true
                        mIndicatorMask.visibility = View.GONE
                    }

                    override fun onTransitionEnd(transition: Transition) {
                        if (!mAnimating) return
                        mAnimating = false
                        if (shouldResize()) {
                            mContainer?.post(doResizeTransition)
                        } else {
                            this@ImageViewerActivity.finish()
                            overridePendingTransition(0, 0)
                        }
                    }
                })

            })
            mBackgroundView.animate().setDuration(ANIMATION_DURATION).alpha(0F).start()
            mBigImageView?.run {
                scaleX = 1F
                scaleY = 1F
                translationX = 0F
                translationY = 0F
            }
            mBigImageView?.ssiv?.run {
                layoutParams = layoutParams.apply {
                    width = mOriginWidth
                    height = mOriginHeight
                    if (this is ViewGroup.MarginLayoutParams) {
                        leftMargin = mOriginLeft
                        topMargin = mOriginTop
                    }
                }
            }
        }
        mContainer?.post(doTransition)
        lifecycle.addObserver(object : LifecycleEventObserver {
            override fun onStateChanged(source: LifecycleOwner, event: Lifecycle.Event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    lifecycle.removeObserver(this)
                    mAnimating = false
                    mContainer?.removeCallbacks(doTransition)
                    if (shouldResize()) mContainer?.removeCallbacks(doResizeTransition)
                    TransitionManager.endTransitions(mContainer as ViewGroup)
                }
            }
        })
    }

    private fun performEnterAnimation() {
        val animatorSet = AnimatorSet()

        val translateXAnimator = ValueAnimator.ofFloat(mBigImageView!!.x, 0F).apply {
            addUpdateListener { va -> mBigImageView?.x = (va.animatedValue as Float) }
        }
        val translateYAnimator = ValueAnimator.ofFloat(mBigImageView!!.y, 0F).apply {
            addUpdateListener { va -> mBigImageView?.y = (va.animatedValue as Float) }
        }
        val scaleYAnimator = ValueAnimator.ofFloat(mScaleY, 1F).apply {
            addUpdateListener { va ->
                if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
                    mBigImageView?.scaleY = (va.animatedValue as Float)
                }
            }
        }
        val scaleXAnimator = ValueAnimator.ofFloat(mScaleX, 1F).apply {
            addUpdateListener { va ->
                if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
                    mBigImageView?.scaleX = (va.animatedValue as Float)
                }
            }
        }
        val backgroundAlphaAnimator = ValueAnimator.ofFloat(0F, 1F).apply {
            addUpdateListener { va -> mBackgroundView.alpha = (va.animatedValue as Float) }
        }

        animatorSet.apply {
            if (mUseEnterAndExitAnimation) {
                playTogether(
                    translateXAnimator,
                    translateYAnimator,
                    scaleXAnimator,
                    scaleYAnimator,
                    backgroundAlphaAnimator
                )
            } else {
                playTogether(backgroundAlphaAnimator)
            }
            duration = ANIMATION_DURATION
            doOnStart { mIndicatorMask.visibility = View.GONE }
            doOnEnd {
                if (mUrlList?.size != 1 || mAnswerEntity != null) {
                    mIndicatorMask.visibility = View.VISIBLE
                }
            }
        }.start()
    }

    private fun performExitAnimation(view: DraggableBigImageView, scale: Float, fadeOnly: Boolean) {
        val finalScale = mOriginWidth / mTargetWidth
        val finalTranslationX = mOriginLeft - (1 - finalScale) * mTargetWidth / 2
        val finalTranslationY =
            mOriginTop - ((1 - finalScale) * mTargetHeight + (mTargetHeight * finalScale - mOriginHeight)) / 2

        val animatorSet = AnimatorSet()

        val scaleAnimator = ValueAnimator.ofFloat(scale, finalScale).apply {
            addUpdateListener { va ->
                if (va.animatedValue is Float && !(va.animatedValue as Float).isNaN() && (va.animatedValue as Float) < Float.MAX_VALUE) {
                    view.scaleX = (va.animatedValue as Float)
                    view.scaleY = (va.animatedValue as Float)
                }
            }
        }
        val translateXAnimator = ValueAnimator.ofFloat(view.x, finalTranslationX).apply {
            addUpdateListener { va -> view.translationX = (va.animatedValue as Float) }
        }
        val translateYAnimator = ValueAnimator.ofFloat(view.y, finalTranslationY).apply {
            addUpdateListener { va -> view.translationY = (va.animatedValue as Float) }
        }
        val backgroundAlphaAnimator = ValueAnimator.ofFloat(mBackgroundView.alpha, 0F).apply {
            addUpdateListener { va -> mBackgroundView.alpha = (va.animatedValue as Float) }
        }
        val alphaAnimator = ValueAnimator.ofFloat(1F, 0F).apply {
            addUpdateListener { va -> view.alpha = (va.animatedValue as Float) }
        }

        if (mUseEnterAndExitAnimation && !fadeOnly) {
            if (mFinalUrl.contains(".gif") || mUrlList!![mViewPager.currentItem].contains(".gif")) {
                animatorSet.apply {
                    playTogether(scaleAnimator, translateXAnimator, translateYAnimator, backgroundAlphaAnimator)
                    doOnEnd {
                        it.removeAllListeners()
                        finish()
                        overridePendingTransition(0, 0)
                    }
                    interpolator = DecelerateInterpolator()
                    duration = ANIMATION_DURATION
                }.start()
            } else {
                startEndTransition()
            }
        } else {
            animatorSet.apply {
                playTogether(backgroundAlphaAnimator, alphaAnimator)
                doOnEnd {
                    it.removeAllListeners()
                    finish()
                    overridePendingTransition(0, 0)
                }
                interpolator = DecelerateInterpolator()
                duration = ANIMATION_DURATION
            }.start()
        }
    }

    private inner class ResizeTransition : Transition() {
        override fun captureStartValues(transitionValues: TransitionValues) {
            captureValues(transitionValues)
        }

        override fun captureEndValues(transitionValues: TransitionValues) {
            captureValues(transitionValues)
        }

        private fun captureValues(transitionValues: TransitionValues) {
            transitionValues.values["width"] = transitionValues.view.width
            transitionValues.values["height"] = transitionValues.view.height
        }

        override fun createAnimator(
            sceneRoot: ViewGroup,
            startValues: TransitionValues?,
            endValues: TransitionValues?
        ): Animator? {
            val startWidth = (startValues?.values?.get("width") as Int?) ?: 0
            val endWidth = (endValues?.values?.get("width") as Int?) ?: 0
            val startHeight = (startValues?.values?.get("height") as Int?) ?: 0
            val endHeight = (endValues?.values?.get("height") as Int?) ?: 0

            val firstValue = if (mViewRatio < mImageRatio) startWidth.toFloat() else startHeight.toFloat()
            val secondValue = if (mViewRatio < mImageRatio) endWidth.toFloat() else endHeight.toFloat()
            return ObjectAnimator.ofFloat(firstValue, secondValue).apply {
                addUpdateListener {
                    sceneRoot.findViewById<BigImageView>(R.id.viewimage_iv_show)?.ssiv?.run {
                        maxScale = scale
                        setMinimumScaleType(SubsamplingScaleImageView.SCALE_TYPE_CENTER_CROP)
                        resetScaleAndCenter()
                    }
                }
            }
        }
    }

    private inner class SsivTransition : Transition() {
        override fun captureStartValues(transitionValues: TransitionValues) {
            captureValues(transitionValues)
        }

        override fun captureEndValues(transitionValues: TransitionValues) {
            captureValues(transitionValues)
        }

        private fun captureValues(transitionValues: TransitionValues) {
            transitionValues.values["width"] = transitionValues.view.width
            transitionValues.values["height"] = transitionValues.view.height
        }

        override fun createAnimator(
            sceneRoot: ViewGroup,
            startValues: TransitionValues?,
            endValues: TransitionValues?
        ): Animator? {
            val startHeight = (startValues?.values?.get("height") as Int?) ?: 0
            val endHeight = (endValues?.values?.get("height") as Int?) ?: 0
            return ObjectAnimator.ofFloat(startHeight.toFloat(), endHeight.toFloat()).apply {
                addUpdateListener {
                    sceneRoot.findViewById<BigImageView>(R.id.viewimage_iv_show)?.ssiv?.run {
                        setScaleAndCenter(minScale, PointF(sWidth / 2F, sHeight / 2F))
                    }
                }
            }
        }
    }

    private inner class ViewImageAdapter : PagerAdapter() {
        override fun getCount() = mUrlList?.size ?: 0

        @SuppressLint("MissingPermission")
        override fun instantiateItem(container: ViewGroup, position: Int): Any {
            val rawUrl = mUrlList!![position]

            var thumbnailImageUrl = if (!mShowBase64Image) {
                ImageUtils.getCachedUrl(rawUrl)
            } else {
                rawUrl
            }
            var compressedStandardImageUrl: String? = if (!mShowBase64Image && rawUrl.contains("ghzs")) {
                // 用 oss.jpeg 加上 limit 以后会出现双指放大的情况
                rawUrl + Config.getSettings()?.image?.oss?.gif
            } else {
                rawUrl
            }
            val imageRequest = ImageRequest.fromUri(thumbnailImageUrl)
            val isInMemoryCache = mImagePipeline!!.isInBitmapMemoryCache(imageRequest)
            val isInDiskCache = imageRequest != null && mImagePipeline!!.isInDiskCacheSync(imageRequest)
            val view = View.inflate(container.context, R.layout.viewimage_normal_item, null) as Gh_RelativeLayout
            val imageView: DraggableBigImageView = view.findViewById(R.id.viewimage_iv_show)
            if (mUseEnterAndExitAnimation) {
                mContainerMap.put(position, view)
            }
            if (mBigImageView == null) {
                mBigImageView = imageView
            }
            imageView.setDragListener(object : DraggableBigImageView.DragListener {
                override fun onRelease(draggableBigImageView: DraggableBigImageView, scale: Float) {
                    updateOriginPosition(mViewPager.currentItem)
                    performExitAnimation(draggableBigImageView, scale, isFadeOnly())
                }

                override fun onDrag(draggableBigImageView: DraggableBigImageView, fraction: Float) {
                    mBackgroundView.alpha = 1 - fraction
                    mIndicatorMask.visibility = View.GONE
                }

                override fun onRestore(draggableBigImageView: DraggableBigImageView, fraction: Float) {
                    mBackgroundView.alpha = 1F
//                    mIndicatorMask.goneIf(mUrlList?.size == 1)
                    if (mUrlList?.size != 1 || mAnswerEntity != null) {
                        mIndicatorMask.visibility = View.VISIBLE
                    }
                }
            })
            // 弱网环境加载低质量图片
            if (!isInMemoryCache
                && !isInDiskCache
                && !NetworkUtils.isWifiOr4GConnected(this@ImageViewerActivity)
                && !thumbnailImageUrl.contains(".gif")
            ) {
                compressedStandardImageUrl = getTransformedUrl(thumbnailImageUrl, mLimitWidth)
                thumbnailImageUrl = compressedStandardImageUrl ?: ""
            }
            val finalUrl = compressedStandardImageUrl
            mFinalUrl = finalUrl ?: ""

            imageView.setImageLoaderCallback(object : SimpleImageLoader() {
                override fun onSuccess(image: File) {
                    if (finalUrl != mUrlList!![position]) {
                        val options = BitmapFactory.Options()
                        options.inJustDecodeBounds = true
                        BitmapFactory.decodeFile(File(image.path).absolutePath, options)
                        loadImageInfo(position, options.outWidth) // 加载图片参数,目的是用户显示原文按钮
                    }
                    val ssiv = imageView.ssiv
                    if (ssiv != null) {
                        ssiv.maxScale = 10f // 这个缩放倍数最好很具宽高自动调节
//                        ssiv.setOnImageEventListener(object : DefaultOnImageEventListener() {
//                            override fun onReady() {
//                                ssiv.resetScaleAndCenter()
//                            }
//                        })
                    }
                    imageView.setOnClickListener {
                        onBackPressed()
                    }
                }
            })
            loadImage(thumbnailImageUrl, compressedStandardImageUrl, imageView)

            //长按
            imageView.setOnLongClickListener {
                // 下滑的时候不弹
                if (imageView.isDragging()) {
                    return@setOnLongClickListener true
                }

                val dialog = Dialog(this@ImageViewerActivity)
                val container1 = LinearLayout(this@ImageViewerActivity)
                container1.orientation = LinearLayout.VERTICAL
                container1.setBackgroundColor(Color.WHITE)
                val reportTv = TextView(this@ImageViewerActivity)
                reportTv.setPadding(
                    DisplayUtils.dip2px(this@ImageViewerActivity, 20f),
                    DisplayUtils.dip2px(this@ImageViewerActivity, 12f),
                    0,
                    DisplayUtils.dip2px(this@ImageViewerActivity, 12f)
                )
                reportTv.setText(R.string.save_pic)
                reportTv.textSize = 17f
                reportTv.setTextColor(ContextCompat.getColor(applicationContext, R.color.title))
                reportTv.setBackgroundResource(R.drawable.textview_white_style)
                val widthPixels = resources.displayMetrics.widthPixels
                reportTv.layoutParams = LinearLayout.LayoutParams(
                    widthPixels * 9 / 10,
                    LinearLayout.LayoutParams.WRAP_CONTENT
                )
                container1.addView(reportTv)
                dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
                dialog.setContentView(container1)
                if (!isFinishing) {
                    dialog.show()
                }
                reportTv.setOnClickListener {
                    checkStoragePermissionBeforeAction {
                        ImageUtils.saveImageToFile(imageView.currentImageFile, finalUrl, mShowBase64Image)
                        dialog.cancel()
                    }
                    dialog.cancel()
                }
                true
            }
            view.tag = position
            container.addView(view)
            return view
        }

        override fun destroyItem(container: ViewGroup, position: Int, `object`: Any) {
            container.removeView(`object` as View)
        }

        override fun isViewFromObject(view: View, `object`: Any): Boolean {
            return view === `object`
        }
    }

    private fun isFadeOnly() =
        mViewPager.currentItem >= mOriginLeftList?.size ?: 0 || mOriginLeft == 0 || mOriginTop == 0

    override fun onBackPressed() {
        updateOriginPosition(mViewPager.currentItem)
        finishWithAnimation(isFadeOnly())
    }

    companion object {
        const val REQUEST_FOR_VIEWED_IMAGE = 921
        const val VIEWED_IMAGE = "viewed_image"
        const val RATIO_DIFF = 0.01F

        @JvmField
        var base64Image: String = ""

        private const val KEY_BASE64 = "base64"
        private const val KEY_URL_LIST = "urls"
        private const val KEY_CURRENT = "current"
        private const val KEY_SHOW_SAVE = "showSave"
        private const val KEY_USE_ENTER_AND_EXIT_ANIMATION = "use_enter_and_exit_animation"
        private const val KEY_IS_FROM_IMAGE_CONTAINER_VIEW = "is_from_image_container_view"

        private const val KEY_LEFT = "left"
        private const val KEY_TOP = "top"
        private const val KEY_HEIGHT = "height"
        private const val KEY_WIDTH = "width"

        private const val ANIMATION_DURATION = 350L
        private const val RESIZE_DURATION = 100L

        @JvmStatic
        fun getBase64Intent(context: Context?, showSingleBase64Image: Boolean): Intent {
            val checkIntent = Intent(context, ImageViewerActivity::class.java)
            checkIntent.putExtra(KEY_BASE64, showSingleBase64Image)
            return checkIntent
        }

        @JvmStatic
        fun getIntent(context: Context, list: ArrayList<String>, position: Int = 0, entrance: String?): Intent {
            return getIntent(context, list, position, null, entrance, false)
        }

        @JvmStatic
        fun getIntent(
            context: Context,
            list: ArrayList<String>,
            position: Int = 0,
            originalViewList: List<View>? = null,
            entrance: String?
        ): Intent {
            return getIntent(context, list, position, originalViewList, entrance, false, null)
        }

        @JvmStatic
        fun getIntent(
            context: Context,
            list: ArrayList<String>,
            position: Int = 0,
            originalViewList: List<View>? = null,
            answerEntity: AnswerEntity? = null,
            entrance: String?,
            isFromICV: Boolean = false
        ): Intent {
            return getIntent(context, list, position, originalViewList, entrance, false, answerEntity, isFromICV)
        }

        /**
         * 传入 viewList 代表使用渐入渐出动画
         */
        @JvmStatic
        fun getIntent(
            context: Context,
            list: ArrayList<String>,
            position: Int = 0,
            originalViewList: List<View>? = null,
            entrance: String?,
            isShowSaveBtn: Boolean,
            answerEntity: AnswerEntity? = null,
            isFromICV: Boolean = false
        ): Intent {
            val intent = Intent(context, ImageViewerActivity::class.java)
            intent.putExtra(KEY_URL_LIST, list)
            intent.putExtra(KEY_CURRENT, position)
            intent.putExtra(KEY_SHOW_SAVE, isShowSaveBtn)
            intent.putExtra(AnswerEntity::class.java.name, answerEntity)
            intent.putExtra(EntranceConsts.KEY_ENTRANCE, entrance)
            intent.putExtra(KEY_IS_FROM_IMAGE_CONTAINER_VIEW, isFromICV)

            if (originalViewList != null) {
                val leftList = arrayListOf<Int>()
                val topList = arrayListOf<Int>()
                val heightList = arrayListOf<Int>()
                val widthList = arrayListOf<Int>()
                for (originalView in originalViewList) {
                    val location = IntArray(2)
                    originalView.getLocationOnScreen(location)
                    leftList.add(location[0])
                    topList.add(location[1])
                    heightList.add(originalView.height)
                    widthList.add(originalView.width)
                }
                intent.putExtra(KEY_LEFT, leftList)
                intent.putExtra(KEY_TOP, topList)
                intent.putExtra(KEY_HEIGHT, heightList)
                intent.putExtra(KEY_WIDTH, widthList)
                intent.putExtra(KEY_USE_ENTER_AND_EXIT_ANIMATION, true)
            }

            if (context is Activity) {
                context.overridePendingTransition(0, 0)
            }

            return intent
        }
    }
}