package com.ama.core.architecture.widget

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.View
import androidx.annotation.AttrRes
import com.ama.core.architecture.R
import androidx.core.content.withStyledAttributes
import androidx.core.graphics.withSave
import com.ama.core.architecture.util.ResUtil

class CircleImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    @AttrRes defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

    private var bitmap: Bitmap? = null
    private val mPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
        isAntiAlias = true
        isDither = true
        color = ResUtil.getColor(R.color.gray_9)
    }
    private val drawRect = RectF()
    private var scaleType = ScaleType.CENTER_CROP
    private var roundRadius = 0f
    private var isCircle = false
    private val path = Path()

    enum class ScaleType {
        FIT_XY, CENTER, CENTER_CROP, CENTER_INSIDE
    }

    init {
        attrs?.let { initAttributes(it, defStyleAttr) }
        setWillNotDraw(false)
    }

    private fun initAttributes(attrs: AttributeSet, defStyleAttr: Int) {
        context.withStyledAttributes(
            attrs, R.styleable.ProtoImageView, defStyleAttr, 0
        ) {
            val srcResource = getResourceId(R.styleable.ProtoImageView_src, 0)
            if (srcResource != 0) {
                setImageResource(srcResource)
            }

            val scaleTypeIndex = getInt(R.styleable.ProtoImageView_scaleType, 2)
            scaleType = ScaleType.values().getOrElse(scaleTypeIndex) { ScaleType.CENTER_CROP }
            roundRadius = getDimension(R.styleable.ProtoImageView_roundRadius, 0f)
            isCircle = getBoolean(R.styleable.ProtoImageView_isCircle, false)
        }
    }

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        val width = getMeasuredSize(widthMeasureSpec, true)
        val height = getMeasuredSize(heightMeasureSpec, false)
        setMeasuredDimension(width, height)
    }

    private fun getMeasuredSize(measureSpec: Int, isWidth: Boolean): Int {
        val mode = MeasureSpec.getMode(measureSpec)
        val size = MeasureSpec.getSize(measureSpec)
        val intrinsicSize = if (isWidth) {
            bitmap?.width ?: 0
        } else {
            bitmap?.height ?: 0
        }

        return when (mode) {
            MeasureSpec.EXACTLY -> size
            MeasureSpec.AT_MOST -> if (intrinsicSize > size) size else intrinsicSize
            else -> intrinsicSize
        }
    }

    override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
        super.onSizeChanged(w, h, oldw, oldh)
        updateDrawRect()
        updatePath()
    }

    private fun updateDrawRect() {
        val bitmap = this.bitmap ?: return
        val viewWidth = width - paddingLeft - paddingRight
        val viewHeight = height - paddingTop - paddingBottom

        drawRect.set(0f, 0f, viewWidth.toFloat(), viewHeight.toFloat())

        when (scaleType) {
            ScaleType.FIT_XY -> {
                // 默认使用drawRect的完整区域
            }
            ScaleType.CENTER -> {
                val left = (viewWidth - bitmap.width) / 2f
                val top = (viewHeight - bitmap.height) / 2f
                drawRect.set(left, top, left + bitmap.width, top + bitmap.height)
            }
            ScaleType.CENTER_CROP -> {
                val scale = Math.max(
                    viewWidth / bitmap.width.toFloat(),
                    viewHeight / bitmap.height.toFloat()
                )
                val scaledWidth = bitmap.width * scale
                val scaledHeight = bitmap.height * scale
                val left = (viewWidth - scaledWidth) / 2
                val top = (viewHeight - scaledHeight) / 2
                drawRect.set(left, top, left + scaledWidth, top + scaledHeight)
            }
            ScaleType.CENTER_INSIDE -> {
                val scale = Math.min(
                    viewWidth / bitmap.width.toFloat(),
                    viewHeight / bitmap.height.toFloat()
                ).coerceAtMost(1f)
                val scaledWidth = bitmap.width * scale
                val scaledHeight = bitmap.height * scale
                val left = (viewWidth - scaledWidth) / 2
                val top = (viewHeight - scaledHeight) / 2
                drawRect.set(left, top, left + scaledWidth, top + scaledHeight)
            }
        }
    }

    private fun updatePath() {
        path.reset()
        when {
            isCircle -> {
                val radius = Math.min(width, height) / 2f
                path.addCircle(width / 2f, height / 2f, radius, Path.Direction.CW)
            }
            roundRadius > 0 -> {
                path.addRoundRect(
                    RectF(0f, 0f, width.toFloat(), height.toFloat()),
                    roundRadius, roundRadius, Path.Direction.CW
                )
            }
            else -> {
                path.addRect(0f, 0f, width.toFloat(), height.toFloat(), Path.Direction.CW)
            }
        }
    }

    override fun onDraw(canvas: Canvas) {
        super.onDraw(canvas)
        val bitmap = this.bitmap ?: return

        canvas.withSave {
            if (isCircle || roundRadius > 0) {
                clipPath(path)
            }
            drawRect(drawRect, mPaint)
            drawBitmap(bitmap, null, drawRect, mPaint)
        }
    }

    fun setImageResource(resId: Int) {
        bitmap = BitmapFactory.decodeResource(resources, resId)
        updateDrawRect()
        updatePath()
        invalidate()
    }

    fun setImageBitmap(bm: Bitmap) {
        bitmap = bm
        updateDrawRect()
        updatePath()
        invalidate()
    }

    fun setScaleType(scaleType: ScaleType) {
        this.scaleType = scaleType
        updateDrawRect()
        invalidate()
    }

    fun setRoundRadius(radius: Float) {
        this.roundRadius = radius
        updatePath()
        invalidate()
    }

    fun setCircle(circle: Boolean) {
        this.isCircle = circle
        updatePath()
        invalidate()
    }
}