package com.base.datarecovery.utils

import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Color
import kotlin.math.sqrt

object TestSimilar {

    private val TAG = "TestSimilar"

    fun testSimilar(srcPath: String, comparePath: String): Boolean {

        //低内存加载
        val srcLowBitmap: Bitmap? = loadBitmapWithLowMemory(srcPath)
        val compareLowBitmap: Bitmap? = loadBitmapWithLowMemory(comparePath)
        if (srcLowBitmap == null || compareLowBitmap == null) {
            return false
        }
        try {
            //缩放
            val srcScaledBitmap = Bitmap.createScaledBitmap(srcLowBitmap, 16, 16, true)
            val compareScaledBitmap = Bitmap.createScaledBitmap(compareLowBitmap, 16, 16, true)
            LogEx.logDebug(TAG, "finish to Scaled with=${srcScaledBitmap.width} height=${srcScaledBitmap.height}")

            //转数组
            val srcBitmapArray = bitmapToFeatureIntArray(srcScaledBitmap)
            val compareBitmapArray = bitmapToFeatureIntArray(compareScaledBitmap)
            srcBitmapArray.forEach {
                LogEx.logDebug(TAG, "finish to IntArray $it")
            }


            //dct转换
            val srcDctArray = dct16x16(srcBitmapArray)
            val compareDctArray = dct16x16(compareBitmapArray)
            LogEx.logDebug(TAG, "finish to DctArray")

            //感知hash转换
            val srcHash = generatePerceptualHash(srcDctArray)
            val compareHash = generatePerceptualHash(compareDctArray)
            LogEx.logDebug(TAG, "srcHash=$srcHash compareHash=$compareHash")

            //对比
            return isImagesSimilar(srcHash, compareHash, 5)

        } catch (e: Exception) {
            LogEx.logDebug(TAG, "$e")
        } finally {
            srcLowBitmap.recycle()
            srcLowBitmap.recycle()
        }

        return false
    }

    private fun loadBitmapWithLowMemory(filePath: String, reqWidth: Int = 16, reqHeight: Int = 16): Bitmap? {
        // 设置BitmapFactory.Options的inJustDecodeBounds为true
        val options = BitmapFactory.Options().apply {
            inJustDecodeBounds = true
            BitmapFactory.decodeFile(filePath, this)
            inJustDecodeBounds = false

            // 计算inSampleSize值
//            inSampleSize = calculateInSampleSize(this, reqWidth, reqHeight)

            // 使用RGB_565配置以减少内存使用
            inPreferredConfig = Bitmap.Config.RGB_565
        }

        // 使用计算得到的options加载Bitmap
        return BitmapFactory.decodeFile(filePath)
    }

    private fun calculateInSampleSize(options: BitmapFactory.Options, reqWidth: Int, reqHeight: Int): Int {
        // 原始图像的宽度和高度
        val height = options.outHeight
        val width = options.outWidth
        var inSampleSize = 1

        // 计算出需要的inSampleSize值
        while (height / inSampleSize > reqHeight || width / inSampleSize > reqWidth) {
            inSampleSize *= 2
        }

        return inSampleSize
    }

    private fun isImagesSimilar(hash1: String, hash2: String, threshold: Int): Boolean {
        return calculateHammingDistance(hash1, hash2) <= threshold
    }

    private fun calculateHammingDistance(hash1: String, hash2: String): Int {
        var distance = 0
        for (i in hash1.indices) {
            if (hash1[i] != hash2[i]) distance++
        }
        return distance
    }

    fun bitmapToFeatureIntArray(bitmap: Bitmap): IntArray {
        // 创建一个整型数组来存储特征，这里我们假设每个像素一个特征值
        val featureSize = bitmap.width * bitmap.height
        val featureIntArray = IntArray(featureSize)

        // 遍历Bitmap的每个像素
        var index = 0
        for (x in 0 until bitmap.width) {
            for (y in 0 until bitmap.height) {
                val pixel = bitmap.getPixel(x, y)
                // 计算灰度值
                val grayValue = getGrayscaleValue(pixel)
                // 存储灰度值到整型数组中
                featureIntArray[index++] = grayValue
            }
        }

        return featureIntArray
    }

    // 辅助函数，用于计算给定像素的灰度值
    fun getGrayscaleValue(color: Int): Int {
        val red = Color.red(color)
        val green = Color.green(color)
        val blue = Color.blue(color)
        // 使用加权和来计算灰度值
        return ((0.299 * red + 0.587 * green + 0.114 * blue).toInt() shl 24) or (color and 0x00FFFFFF)
    }

    fun dct16x16(block: IntArray): DoubleArray {
        val N = 16 // 变换的尺寸
        val scaledBlock = DoubleArray(N * N)

        for (u in 0 until N) {
            for (v in 0 until N) {
                var sum = 0.0
                for (x in 0 until N) {
                    for (y in 0 until N) {
                        // 应用DCT变换公式
                        sum += block[x * N + y] *
                                Math.cos((2.0 * x + 1.0) * u * Math.PI / (2.0 * N)) *
                                Math.cos((2.0 * y + 1.0) * v * Math.PI / (2.0 * N))
                    }
                }
                // 标准化因子，当u或v为0时，使用1/sqrt(N)，否则使用1/N
                val norm = if (u == 0 && v == 0) (1.0 / sqrt(N.toDouble())) else (1.0 / N)
                scaledBlock[u * N + v] = sum * norm
            }
        }

        return scaledBlock
    }

    private fun generatePerceptualHash(dctCoefficients: DoubleArray): String {
        // 1. 截断DCT系数，假设dctCoefficients已经是16x16的DCT系数
        // 保留8x8的系数块，这里简化处理，只取前64个系数
        val truncatedDctCoefficients = dctCoefficients.take(64)

        // 2. 量化DCT系数，将系数映射到0-1范围，然后四舍五入到最近的整数
        val quantizedCoefficients = truncatedDctCoefficients.map {
            ((it + 128) / 255 * 0.5).coerceIn(0.0, 1.0).toInt()
        }

        // 3. 生成哈希值，将量化后的系数转换为二进制字符串
        val hashBuilder = StringBuilder()
        quantizedCoefficients.forEach {
            // 将每个量化系数转换为二进制表示，并添加到哈希构建器中
            hashBuilder.append(it.toString(2))
        }

        // 返回最终的哈希值字符串
        return hashBuilder.toString()
    }


}