package com.cr.view

import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.GestureDetector
import android.view.MotionEvent
import android.view.ScaleGestureDetector
import androidx.appcompat.widget.AppCompatImageView
import androidx.core.graphics.drawable.toBitmap
import com.cr.common.CrFileManager
import com.cr.cruav.R
import com.cr.data.CrUtil
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream

/**
 * 操作系统：MAC系统
 * 创建者：王成
 * 创建日期：2023/6/20 11:03
 * 描述：图片编辑视图
 */
class CrImageEditor @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null
) : AppCompatImageView(context, attrs) {
    // todo: 2023/8/26 视图尺寸定义
    private var viewWidth: Int = 0  // define: 2023/8/26 视图宽度
    private var viewHeight: Int = 0  // define: 2023/8/26 视图高度

    // todo: 2023/9/28 监听事件
    private var mScaleGestureDetector: ScaleGestureDetector? = null // define: 2023/6/20 缩放
    private var mGestureDetector: GestureDetector? = null  // define: 2023/6/20 平移

    // todo: 2023/6/20 缩放平移矩阵
    private var mCurrentMatrix = Matrix()

    // todo: 2023/9/28 变量定义
    private var mCenterX: Float? = 0f  // define: 2023/9/28 : 2023/6/20 最小缩放
    private var mCenterY: Float? = 0f
    private var drawPoints = mutableListOf<PointF>() // define: 2023/6/20 绘制点集合
    private var downPoints = mutableListOf<PointF>()  // define: 2023/6/21 点击点集合

    // todo: 2023/6/20 画笔
    private var drawPointPaint = Paint()
    private var drawLinePaint = Paint()

    // todo: 2023/9/28 展示文件定义
    private var fileAllPath: String? = null  // define: 2023/9/28 全路径
    private var fileName: String? = null  // define: 2023/9/28 不含扩展名的文件名
    private var extensionName: String? = null // define: 2023/9/28 扩展名

    // todo: 2023/9/28 显示图
    private var viewBitmap: Bitmap? = null

    /**
     * 缩放监听
     */
    private val mScaleListener = object : ScaleGestureDetector.SimpleOnScaleGestureListener() {
        // todo: 2023/6/20 缩放开始
        override fun onScaleBegin(detector: ScaleGestureDetector): Boolean {
            return true
        }

        // todo: 2023/6/20 缩放中
        override fun onScale(detector: ScaleGestureDetector): Boolean {
            var scaleFactor = detector?.scaleFactor
            if (mCenterX == 0f) {
                // todo: 2023/6/20 最小X轴缩放
                mCenterX = width / 2f
            }
            if (mCenterY == 0f) {
                // todo: 2023/6/20 最小Y轴缩放
                mCenterY = height / 2f
            }
            // todo: 2023/6/21 缩放变换
            mCurrentMatrix.postScale(scaleFactor!!, scaleFactor!!, mCenterX!!, mCenterY!!)
            invalidate()
            return true
        }

        // todo: 2023/6/20 缩放结束
        override fun onScaleEnd(detector: ScaleGestureDetector) {
            super.onScaleEnd(detector)
        }
    }


    /**
     * 平移监听
     */
    private val mTranslationListener = object : GestureDetector.SimpleOnGestureListener() {
        // todo: 2023/6/20 单击确认
        override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
            // todo: 2023/6/20 单击绘制一个点 试试
            val point = PointF(e.x, e.y)
            // todo: 2023/6/21 由于缩放后点击，点击位置已经经过矩阵变换，为统一在重绘时变换，需要逆向变换一次
            downPoints.add(calculateInversePointF(point, mCurrentMatrix))
            // todo: 2023/6/21 重绘
            invalidate()
            return true
        }

        // todo: 2023/6/20 移动
        override fun onScroll(
            e1: MotionEvent,
            e2: MotionEvent,
            distanceX: Float,
            distanceY: Float
        ): Boolean {
            // todo: 2023/6/21 设置变化矩阵
            mCurrentMatrix.postTranslate(-distanceX, -distanceY)
            // todo: 2023/6/21 重绘
            invalidate()
            return true
        }
    }

    /**
     * 根据矩阵计算点位置
     * @param pointF PointF 变化前
     * @param matrix Matrix 矩阵
     * @return PointF 变化后
     */
    private fun calculatePointF(pointF: PointF, matrix: Matrix): PointF {
        // todo: 2023/6/21 返回点
        var resPointF = PointF()
        // todo: 2023/6/21 获取矩阵数据
        var matrixValue = FloatArray(9)
        matrix.getValues(matrixValue)
        // todo: 2023/6/21 计算
        resPointF.x = pointF.x * matrixValue[0] + matrixValue[2]
        resPointF.y = pointF.y * matrixValue[4] + matrixValue[5]
        // todo: 2023/6/21 返回
        return resPointF
    }

    /**
     * 根据矩阵反向计算点位置
     * @param pointF PointF 变化前
     * @param matrix Matrix 变换矩阵
     * @return PointF 变化后
     */
    private fun calculateInversePointF(pointF: PointF, matrix: Matrix): PointF {
        // todo: 2023/6/21 返回点
        var resPointF = PointF()
        // todo: 2023/6/21 反转矩阵
        var inverseMatrix = Matrix()
        matrix.invert(inverseMatrix)
        // todo: 2023/6/21 获取矩阵数据
        var matrixValue = FloatArray(9)
        inverseMatrix.getValues(matrixValue)
        // todo: 2023/6/21 计算
        resPointF.x = pointF.x * matrixValue[0] + matrixValue[2]
        resPointF.y = pointF.y * matrixValue[4] + matrixValue[5]
        // todo: 2023/6/21 返回
        return resPointF
    }


    /**
     * 初始化
     */
    init {
        // todo: 2023/6/20 初始化平移、缩放监听
        mScaleGestureDetector = ScaleGestureDetector(context, mScaleListener)
        mGestureDetector = GestureDetector(context, mTranslationListener)
        // todo: 2023/6/20 初始化点画笔
        drawPointPaint.color = Color.BLUE
        drawPointPaint.isAntiAlias = true
        drawPointPaint.strokeWidth = 20f
        // todo: 2023/6/20 初始化线画笔
        drawLinePaint.color = context!!.getColor(R.color.line_4)
        drawLinePaint.isAntiAlias = true
        drawLinePaint.strokeWidth = 3.0f
    }

    /**
     * 重置
     * @param widthMeasureSpec Int
     * @param heightMeasureSpec Int
     */
    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        // todo: 2023/8/26 获取视图宽度和高度 单位是像素
        this.viewWidth = MeasureSpec.getSize(widthMeasureSpec)
        this.viewHeight = MeasureSpec.getSize(heightMeasureSpec)
    }

    /**
     * 绘制
     * @param canvas Canvas
     */
    override fun onDraw(canvas: Canvas?) {
        var saveCount = canvas?.save()
        canvas?.concat(mCurrentMatrix)
        super.onDraw(canvas)
        canvas?.restoreToCount(saveCount!!)

        // todo: 2023/6/21 变换
        drawPoints.clear()
        for (point in downPoints) {
            drawPoints.add(calculatePointF(point, mCurrentMatrix))
        }
        // todo: 2023/6/20 绘制点
        drawPoint(canvas,drawPoints)
        // todo: 2023/9/28 绘制线
        drawLine(canvas,drawPoints)
    }

    /**
     * 绘制点
     * @param canvas Canvas? 画布
     * @param points List<PointF> 数据集合
     */
    private fun drawPoint(canvas: Canvas?,points:List<PointF>) {
        // todo: 2023/6/20 绘制点
        for (point in points) {
            canvas?.drawPoint(point.x, point.y, drawPointPaint)
        }
    }

    /**
     * 绘制线
     * @param canvas Canvas? 画布
     * @param points List<PointF> 数据集合
     */
    private fun drawLine(canvas: Canvas?,points:List<PointF>) {
        // todo: 2023/6/20 绘制线
        if (points.size > 1) {
            var dPoints = mutableListOf<Float>()
            for (i in 0 until points.size - 1) {
                var point1 = points[i]
                var point2 = points[i + 1]
                dPoints.add(point1.x)
                dPoints.add(point1.y)
                dPoints.add(point2.x)
                dPoints.add(point2.y)
            }
            // todo: 2023/9/28 闭合线
            if (points.size > 2) {
                dPoints.add(points.last().x)
                dPoints.add(points.last().y)
                dPoints.add(points.first().x)
                dPoints.add(points.first().y)
            }
            canvas?.drawLines(dPoints.toFloatArray(), drawLinePaint)
        }
    }

    /**
     * 覆写Touch事件
     * @param event MotionEvent
     * @return Boolean
     */
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        // todo: 2023/6/20 这里将触摸事件转接给ScaleGestureDetector与GestureDetector
        mScaleGestureDetector?.onTouchEvent(event!!)
        if (mScaleGestureDetector?.isInProgress == false) {
            mGestureDetector?.onTouchEvent(event!!)
        }
        return true
    }

    /**
     * 设置线的宽度
     * @param width Float 线的宽度
     */
    fun crSetLineWidth(width: Float) {
        drawLinePaint.strokeWidth = width
        // todo: 2023/6/26 重绘
        invalidate()
    }

    /**
     * 设置线的颜色
     * @param color Int 线的颜色
     */
    fun crSetLineColor(color: Int) {
        drawLinePaint.color = color
        // todo: 2023/6/26 重绘
        invalidate()
    }

    /**
     * 回退撤销一步
     */
    fun crSetUndo() {
        if (this.downPoints.size > 0) {
            this.downPoints.removeLast()
            invalidate()
        }
    }

    /**
     * 重绘
     */
    fun crReset() {
        this.downPoints.clear()
        invalidate()
    }

    /**
     * 设置显示的图片
     * @param fileAllPath String 全路径
     */
    fun crSetBitmap(fileAllPath: String) {
        this.fileAllPath = fileAllPath
        this.fileName = CrFileManager.getFileNoExtensionName(fileAllPath)
        this.extensionName = CrFileManager.getExtensionName(fileAllPath)
        // todo: 2023/9/28 设置显示图片
        var file = File(fileAllPath)
        if (file.exists()) {
            val fis = FileInputStream(fileAllPath)
            viewBitmap = BitmapFactory.decodeStream(fis)
            this.setImageBitmap(viewBitmap!!)
        }
    }

    /**
     * 保存图片
     * @return String? 返回保存的图片名称
     */
    fun crSaveImage(): String? {
        viewBitmap?.let {
            // todo: 2023/9/28 为了保证最终保存的绘制内容与图片对应 需要通过矩阵进行变换
            var matrix = Matrix()  // todo: 2023/9/28 定义一个矩阵
            // todo: 2023/9/28 计算缩放比例
            if(viewWidth<viewHeight) {
                // todo: 2023/9/28 进行缩放
                val imgScale = (it.width*1.0f)/(viewWidth*1.0f)
                matrix.postScale(imgScale,imgScale)
                // todo: 2023/9/28 平移
                val imgTranslate = (viewHeight*imgScale - it.height)*0.5f
                matrix.postTranslate(0f,-1*imgTranslate)
            } else{
                // todo: 2023/9/28 进行缩放
                val imgScale = (it.height*1.0f)/(viewHeight*1.0f)
                matrix.postScale(imgScale,imgScale)
                // todo: 2023/9/28 平移
                val imgTranslate = (viewWidth*imgScale - it.width)*0.5f
                matrix.postTranslate(-1*imgTranslate,0f)
            }
            // todo: 2023/9/28 创建一个bitmap
            var saveBitmap = Bitmap.createBitmap(it.width,it.height,it.config)
            // todo: 2023/9/28 创建一个画布
            var canvas = Canvas(saveBitmap)
            // todo: 2023/9/28 绘制图片
            val picturePaint = Paint()
            canvas.drawBitmap(it,0f,0f,picturePaint)
            // todo: 2023/6/21 变换
            var dPoints = mutableListOf<PointF>()
            for (point in downPoints) {
                val resPoint = calculatePointF(point, matrix)
                dPoints.add(resPoint)
            }
            // todo: 2023/9/28 绘制线
            drawLine(canvas,dPoints)
            // todo: 2023/9/28 保存
            val outFileName = "${this.fileName}_new.${this.extensionName}"
            val outFilePath = "${CrUtil.IMAGE_PATH}${outFileName}"
            // todo: 2023/9/28 如果文件存在 先删除
            var file = File(outFilePath)
            if(file.exists()){
                file.delete()
            }
            val outFileStream = FileOutputStream(outFilePath)
            saveBitmap.compress(Bitmap.CompressFormat.JPEG, 100, outFileStream)
            outFileStream.flush()
            outFileStream.close()
            return outFileName
        }
        return null
    }
}