package com.base.scanqrclear.qr

import android.content.Context
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Matrix
import android.graphics.Point
import androidx.annotation.ColorInt
import com.base.scanqrclear.bean.QrStyleBean
import com.base.scanqrclear.utils.AssetReader
import com.base.scanqrclear.utils.LogEx
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import com.google.zxing.BarcodeFormat
import com.google.zxing.EncodeHintType
import com.google.zxing.WriterException
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import org.json.JSONObject
import java.util.Hashtable
import kotlin.math.atan2
import kotlin.math.pow
import kotlin.math.sqrt


object QrStyleUtils {

    private val TAG = "QrStyleUtils"


    fun Context.getQrStyleBean(): List<QrStyleBean>? {

        // 读取 JSON 文件
        val jsonString: String = AssetReader().readJsonFromAssets(this, "qr_code_style.json")
        try {

            // 将 JSON 字符串解析为 JSONObject
            val jsonObject = JSONObject(jsonString)

            // 获取 "data" 对象
            val dataObject = jsonObject.getJSONObject("data")

            // 获取 "list" 数组
            val listArray = dataObject.getJSONArray("list")


            val type = object : TypeToken<List<QrStyleBean>>() {}.type

            val list = Gson().fromJson<List<QrStyleBean>>(listArray.toString(), type)

            return list
        } catch (e: Exception) {

        }

        return null
    }


    /**
     * 生成带有背景图片的二维码，并根据四个角点坐标调整二维码方向
     *
     * @param content 二维码内容
     * @param backgroundBitmap 背景图片
     * @param points 四个角点坐标 (257,540), (540,823), (823,540), (540,257)
     * @return 合成后的二维码图片
     */
    fun generateQRCodeWithBackground(
        content: String,
        backgroundBitmap: Bitmap,
        points: List<Point>,
        scale: Float,
        @ColorInt qrColor: Int,
        @ColorInt qrBgColor: Int
    ): Bitmap? {
        // 1. 计算二维码的宽度和高度
        val size = calculateQRSize(points)
        // 2. 生成二维码
        val qrCodeBitmap = createQRCodeBitmap(content, size.first, size.second, qrColor, qrBgColor)

        qrCodeBitmap?.let {
            // 3. 计算旋转角度
            val rotationAngle = calculateRotationAngle(points)
            LogEx.logDebug(TAG, "rotationAngle=$rotationAngle")

            // 4. 旋转二维码
            val rotatedQRCodeBitmap = rotateBitmap(it, rotationAngle)

            // 5. 合成背景图片和二维码
            return combineBitmaps(backgroundBitmap, rotatedQRCodeBitmap, points, scale)
        }
        return null
    }

    /**
     * 根据四个角点坐标计算二维码的宽度和高度
     */
    private fun calculateQRSize(points: List<Point>): Pair<Int, Int> {
        if (points.size != 4) throw IllegalArgumentException("Four points are required")

        val p1 = points[0]
        val p2 = points[1]
        val p3 = points[2]
        val p4 = points[3]

        // 计算对角线距离
        val diagonal1 = distanceBetweenPoints(p1, p3)
        val diagonal2 = distanceBetweenPoints(p2, p4)

        // 取对角线的平均值作为二维码的边长
        val qrSize = ((diagonal1 + diagonal2) / 2).toInt()

        // 假设二维码是正方形，宽高相同
        return Pair(qrSize, qrSize)
    }

    /**
     * 计算两点之间的距离
     */
    private fun distanceBetweenPoints(p1: Point, p2: Point): Float {
        return sqrt((p2.x - p1.x).toDouble().pow(2) + (p2.y - p1.y).toDouble().pow(2)).toFloat()
    }

    /**
     * 生成二维码 Bitmap
     */
    private fun createQRCodeBitmap(content: String, width: Int, height: Int, qrColor: Int, qrBgColor: Int): Bitmap? {
        if (width < 0 || height < 0) return null
        val hints = Hashtable<EncodeHintType, Any>().apply {
            this[EncodeHintType.CHARACTER_SET] = "UTF-8"
            this[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
            this[EncodeHintType.MARGIN] = 0
        }
        return try {
            val bitMatrix = QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints)
            val pixels = IntArray(width * height)
            for (y in 0 until height) {
                for (x in 0 until width) {
                    pixels[y * width + x] = if (bitMatrix[x, y]) qrColor else qrBgColor
                }
            }
            Bitmap.createBitmap(pixels, width, height, Bitmap.Config.ARGB_8888)
        } catch (e: WriterException) {
            e.printStackTrace()
            null
        }
    }

    /**
     * 计算旋转角度
     */
    private fun calculateRotationAngle(points: List<Point>): Float {
        // 使用左上角和右下角的坐标计算斜率
        val dx = points[1].x - points[0].x
        val dy = points[1].y - points[0].y
        return Math.toDegrees(atan2(dy.toDouble(), dx.toDouble())).toFloat()
    }

    /**
     * 旋转 Bitmap
     */
    private fun rotateBitmap(bitmap: Bitmap, angle: Float): Bitmap {
        val matrix = Matrix().apply {
            postRotate(angle, bitmap.width / 2f, bitmap.height / 2f)
        }
        return Bitmap.createBitmap(bitmap, 0, 0, bitmap.width, bitmap.height, matrix, true)
    }

    /**
     * 合成背景图片和二维码
     */
    private fun combineBitmaps(background: Bitmap, qrCode: Bitmap, points: List<Point>, scale: Float): Bitmap {

        // 1. 计算四个角点的中心点
        val centerX = (points[0].x + points[1].x + points[2].x + points[3].x) / 4f
        val centerY = (points[0].y + points[1].y + points[2].y + points[3].y) / 4f

        // 2. 等比缩小二维码
        val scaledWidth = (qrCode.width * scale).toInt()
        val scaledHeight = (qrCode.height * scale).toInt()
        val scaledQRCode = Bitmap.createScaledBitmap(qrCode, scaledWidth, scaledHeight, true)

        // 3. 创建合成后的图片
        val combinedBitmap = Bitmap.createBitmap(background.width, background.height, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(combinedBitmap)
        canvas.drawBitmap(background, 0f, 0f, null)

        // 5. 计算二维码的绘制位置，使其中心点与四个角点的中心点对齐
        val qrCenterX = scaledQRCode.width / 2f
        val qrCenterY = scaledQRCode.height / 2f
        val qrLeft = centerX - qrCenterX
        val qrTop = centerY - qrCenterY
        canvas.drawBitmap(scaledQRCode, qrLeft, qrTop, null)

        return combinedBitmap
    }

}