package com.adealink.weparty.commonui.imageview

import android.content.Context
import android.graphics.drawable.Drawable
import android.graphics.drawable.LayerDrawable
import android.util.AttributeSet
import androidx.appcompat.widget.AppCompatImageView
import com.adealink.weparty.R

class CircleRippleImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyle: Int = 0,
) : AppCompatImageView(context, attrs, defStyle) {
    private var mOuterBorderWidth: Int
    private var mOuterBorderColor: Int
    private var mInnerBorderWidth: Int
    private var mInnerBorderColor: Int
    private val mCircleBackground: Boolean
    private var mRippleWidth: Float
    private var mRippleSpace: Float
    private var mRippleColor: Int
    private var mRippleSpeed: Long
    private var mRippleStartAlphaDuration: Long
    private var mRippleEndAlphaDuration: Long
    private val mShaderOuterBorder: Boolean
    private val mResource = 0
    private val mDrawable: Drawable
    private val mBackgroundDrawable: Drawable? = null
    private var mScaleType: ScaleType? = null
    override fun drawableStateChanged() {
        super.drawableStateChanged()
        invalidate()
    }

    private fun updateDrawableAttrs() {
        updateAttrs(mDrawable, false)
    }

    private fun updateAttrs(drawable: Drawable?, background: Boolean) {
        if (drawable == null) {
            return
        }
        if (drawable is CircleDrawable) {
            drawable.setScaleType(mScaleType)
                .setOuterBorderWidth(if (background && !mCircleBackground) 0 else mOuterBorderWidth)
                .setOuterBorderColor(mOuterBorderColor)
                .setInnerBorderWidth(if (background && !mCircleBackground) 0 else mInnerBorderWidth)
                .setInnerBorderColor(mInnerBorderColor).setRippleColor(mRippleColor)
                .setRippleEndAlphaDuration(mRippleEndAlphaDuration)
                .setRippleSpace(mRippleSpace).setRippleSpeed(mRippleSpeed)
                .setRippleStartAlphaDuration(mRippleStartAlphaDuration)
                .setRippleWidth(mRippleWidth).setShaderOuterBorder(mShaderOuterBorder)
        } else if (drawable is LayerDrawable) {
            // loop through layers to and set drawable attrs
            val layers = drawable.numberOfLayers
            for (i in 0 until layers) {
                updateAttrs(drawable.getDrawable(i), background)
            }
        }
    }

    private fun updateBackgroundDrawableAttrs() {
        updateAttrs(mBackgroundDrawable, true)
    }

    override fun getScaleType(): ScaleType {
        return mScaleType!!
    }

    fun getScaleTypeByIndex(index: Int): ScaleType? {
        return if (index < 0 || index >= SCALE_TYPES.size) {
            null
        } else SCALE_TYPES[index]
    }

    override fun setScaleType(scaleType: ScaleType) {
        if (mScaleType != scaleType) {
            mScaleType = scaleType
            when (scaleType) {
                ScaleType.CENTER, ScaleType.CENTER_CROP, ScaleType.CENTER_INSIDE, ScaleType.FIT_CENTER, ScaleType.FIT_START, ScaleType.FIT_END, ScaleType.FIT_XY -> super.setScaleType(
                    ScaleType.FIT_XY)
                else -> super.setScaleType(scaleType)
            }
            updateDrawableAttrs()
            updateBackgroundDrawableAttrs()
            invalidate()
        }
    }

    var outerBorderWidth: Int
        get() = mOuterBorderWidth
        set(width) {
            if (mOuterBorderWidth == width) {
                return
            }
            mOuterBorderWidth = width
            updateDrawableAttrs()
            updateBackgroundDrawableAttrs()
            invalidate()
        }
    var innerBorderWidth: Int
        get() = mInnerBorderWidth
        set(width) {
            if (mInnerBorderWidth == width) {
                return
            }
            mInnerBorderWidth = width
            updateDrawableAttrs()
            updateBackgroundDrawableAttrs()
            invalidate()
        }
    var outerBorderColor: Int
        get() = mOuterBorderColor
        set(color) {
            if (mOuterBorderColor == color) {
                return
            }
            mOuterBorderColor = color
            updateDrawableAttrs()
            updateBackgroundDrawableAttrs()
        }

    @Synchronized
    fun startRipple() {
        if (mDrawable is CircleDrawable) {
            val drawable: CircleDrawable = mDrawable
            if (!drawable.isRippleStarted) {
                drawable.startRipple()
            }
        } else {

        }
    }

    @Synchronized
    fun stopRipple() {
        if (mDrawable is CircleDrawable) {
            val drawable: CircleDrawable = mDrawable as CircleDrawable
            drawable.stopRipple()
        } else {

        }
    }

    fun showRipple() {
        if (mDrawable is CircleDrawable) {
            (mDrawable as CircleDrawable).showRipple()
        } else {

        }
    }

    fun hideRipple() {
        if (mDrawable is CircleDrawable) {
            (mDrawable as CircleDrawable).hideRipple()
        } else {

        }
    }

    fun setInnerBorderColor(color: Int) {
        mInnerBorderColor = color
        if (mDrawable is CircleDrawable) {
            (mDrawable as CircleDrawable).setInnerBorderColor(color)
        } else {

        }
    }

    fun setRippleColor(rippleColor: Int) {
        mRippleColor = rippleColor
        if (mDrawable is CircleDrawable) {
            (mDrawable as CircleDrawable).setRippleColor(rippleColor)
        } else {

        }
    }

    fun setShowInnerBorderAlways(showAlways: Boolean) {
        if (mDrawable is CircleDrawable) {
            val draw: CircleDrawable = mDrawable as CircleDrawable
            draw.setShowInnerBorderAlways(showAlways)
        } else {

        }
    }

    fun showInnerBorder() {
        if (mDrawable is CircleDrawable) {
            val draw: CircleDrawable = mDrawable as CircleDrawable
            if (!draw.isRippleStarted) {
                draw.invalidateSelf()
            }
        } else {

        }
    }

    private val isRippleStarted: Boolean
        private get() {
            if (mDrawable is CircleDrawable) {
                val drawable: CircleDrawable = mDrawable as CircleDrawable
                return drawable.isRippleStarted
            }
            return false
        }

    private fun restartRipple() {

        stopRipple()
        startRipple()
    }

    fun setRippleWidth(valuePx: Int) {
        mRippleWidth = valuePx.toFloat()
    }

    fun setRippleSpace(valuePx: Int) {
        mRippleSpace = valuePx.toFloat()
    }

    fun setRippleSpeed(speed: Int) {
        mRippleSpeed = speed.toLong()
    }

    fun setRippleEndAlphaDuration(duration: Long) {
        mRippleEndAlphaDuration = duration
    }

    fun setRippleStartAlphaDuration(duration: Long) {
        mRippleStartAlphaDuration = duration
    }

    companion object {
        const val TAG = "CircleRippleImageView"
        private val SCALE_TYPES = arrayOf(ScaleType.MATRIX,
            ScaleType.FIT_XY,
            ScaleType.FIT_START,
            ScaleType.FIT_CENTER,
            ScaleType.FIT_END,
            ScaleType.CENTER,
            ScaleType.CENTER_CROP,
            ScaleType.CENTER_INSIDE)
        private const val RIPPLE_DURATION = 1500
    }

    init {
        val a =
            context.obtainStyledAttributes(attrs, R.styleable.CircleRippleImageView, defStyle, 0)
        val index = a.getInt(R.styleable.CircleRippleImageView_android_scaleType, -1)
        scaleType = if (index >= 0) {
            SCALE_TYPES[index]
        } else {
            ScaleType.CENTER_CROP
        }
        mOuterBorderWidth =
            a.getDimensionPixelSize(R.styleable.CircleRippleImageView_outer_border_width, 10)
        // don't allow negative values for radius and border
        if (mOuterBorderWidth < 0) {
            mOuterBorderWidth = 0
        }
        mOuterBorderColor = a.getColor(R.styleable.CircleRippleImageView_outer_border_color,
            CircleDrawable.DEFAULT_OUTER_BORDER_COLOR)
        mInnerBorderWidth =
            a.getDimensionPixelSize(R.styleable.CircleRippleImageView_inner_border_width, 3)
        // don't allow negative values for radius and border
        if (mInnerBorderWidth < 0) {
            mInnerBorderWidth = 0
        }
        mInnerBorderColor = a.getColor(R.styleable.CircleRippleImageView_inner_border_color,
            CircleDrawable.DEFAULT_OUTER_BORDER_COLOR)
        mCircleBackground =
            a.getBoolean(R.styleable.CircleRippleImageView_circle_background, false)
        mRippleSpeed = a.getInt(R.styleable.CircleRippleImageView_ripple_speed, 500).toLong()
        mRippleSpace =
            a.getDimensionPixelSize(R.styleable.CircleRippleImageView_ripple_space, 5).toFloat()
        mRippleColor = a.getColor(R.styleable.CircleRippleImageView_ripple_color, -1)
        if (mRippleColor == -1) {
            mRippleColor = CircleDrawable.DEFAULT_OUTER_BORDER_COLOR
        }
        mRippleWidth =
            a.getDimensionPixelSize(R.styleable.CircleRippleImageView_ripple_width, 2).toFloat()
        mRippleStartAlphaDuration =
            a.getInt(R.styleable.CircleRippleImageView_ripple_start_alpha_duration, 1000).toLong()
        mRippleEndAlphaDuration =
            a.getInt(R.styleable.CircleRippleImageView_ripple_end_alpha_duration, 500).toLong()
        mShaderOuterBorder =
            a.getBoolean(R.styleable.CircleRippleImageView_shader_outer_border, true)
        mDrawable = CircleDrawable.fromSize(30, 30)
        updateDrawableAttrs()
        super.setImageDrawable(mDrawable)
        updateBackgroundDrawableAttrs()
        a.recycle()
    }
}