package com.placeholder.sherpai2.ui.trainingprep

import android.content.Context
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.net.Uri
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.withContext
import java.io.InputStream

/**
 * Helper class for detecting duplicate or near-duplicate images using perceptual hashing
 */
class DuplicateImageDetector(private val context: Context) {

    data class DuplicateCheckResult(
        val hasDuplicates: Boolean,
        val duplicateGroups: List<DuplicateGroup>,
        val uniqueImageCount: Int
    )

    data class DuplicateGroup(
        val images: List<Uri>,
        val similarity: Double
    )

    private data class ImageHash(
        val uri: Uri,
        val hash: Long
    )

    /**
     * Check for duplicate images in the provided list
     */
    suspend fun checkForDuplicates(
        uris: List<Uri>,
        similarityThreshold: Double = 0.95
    ): DuplicateCheckResult = withContext(Dispatchers.Default) {
        if (uris.size < 2) {
            return@withContext DuplicateCheckResult(
                hasDuplicates = false,
                duplicateGroups = emptyList(),
                uniqueImageCount = uris.size
            )
        }

        // Compute perceptual hash for each image
        val imageHashes = uris.mapNotNull { uri ->
            try {
                val bitmap = loadBitmap(uri)
                bitmap?.let {
                    val hash = computePerceptualHash(it)
                    ImageHash(uri, hash)
                }
            } catch (e: Exception) {
                null
            }
        }

        // Find duplicate groups
        val duplicateGroups = mutableListOf<DuplicateGroup>()
        val processed = mutableSetOf<Uri>()

        for (i in imageHashes.indices) {
            if (imageHashes[i].uri in processed) continue

            val currentGroup = mutableListOf(imageHashes[i].uri)

            for (j in i + 1 until imageHashes.size) {
                if (imageHashes[j].uri in processed) continue

                val similarity = calculateSimilarity(imageHashes[i].hash, imageHashes[j].hash)

                if (similarity >= similarityThreshold) {
                    currentGroup.add(imageHashes[j].uri)
                    processed.add(imageHashes[j].uri)
                }
            }

            if (currentGroup.size > 1) {
                duplicateGroups.add(
                    DuplicateGroup(
                        images = currentGroup,
                        similarity = 1.0
                    )
                )
                processed.addAll(currentGroup)
            }
        }

        DuplicateCheckResult(
            hasDuplicates = duplicateGroups.isNotEmpty(),
            duplicateGroups = duplicateGroups,
            uniqueImageCount = uris.size - duplicateGroups.sumOf { it.images.size - 1 }
        )
    }

    /**
     * Compute perceptual hash using difference hash (dHash) algorithm
     */
    private fun computePerceptualHash(bitmap: Bitmap): Long {
        // Resize to 9x8
        val resized = Bitmap.createScaledBitmap(bitmap, 9, 8, false)

        var hash = 0L
        var bitIndex = 0

        for (y in 0 until 8) {
            for (x in 0 until 8) {
                val leftPixel = resized.getPixel(x, y)
                val rightPixel = resized.getPixel(x + 1, y)

                val leftGray = toGrayscale(leftPixel)
                val rightGray = toGrayscale(rightPixel)

                if (leftGray > rightGray) {
                    hash = hash or (1L shl bitIndex)
                }
                bitIndex++
            }
        }

        resized.recycle()
        return hash
    }

    /**
     * Convert RGB pixel to grayscale value
     */
    private fun toGrayscale(pixel: Int): Int {
        val r = (pixel shr 16) and 0xFF
        val g = (pixel shr 8) and 0xFF
        val b = pixel and 0xFF
        return (0.299 * r + 0.587 * g + 0.114 * b).toInt()
    }

    /**
     * Calculate similarity between two hashes
     */
    private fun calculateSimilarity(hash1: Long, hash2: Long): Double {
        val xor = hash1 xor hash2
        val hammingDistance = xor.countOneBits()
        return 1.0 - (hammingDistance / 64.0)
    }

    /**
     * Load bitmap from URI
     */
    private fun loadBitmap(uri: Uri): Bitmap? {
        return try {
            val inputStream: InputStream? = context.contentResolver.openInputStream(uri)
            BitmapFactory.decodeStream(inputStream)?.also {
                inputStream?.close()
            }
        } catch (e: Exception) {
            null
        }
    }
}