package eu.geyskens.pdfscan.scan

import android.graphics.PointF
import androidx.camera.core.ImageAnalysis
import androidx.camera.core.ImageProxy
import org.opencv.core.Core
import org.opencv.core.CvType
import org.opencv.core.Mat

/**
 * Runs [EdgeDetector] on live camera frames (throttled) and reports the detected document
 * corners, normalized to a display-oriented frame, together with that frame's aspect ratio
 * (width / height) so the overlay can map them onto the preview.
 */
class DocumentAnalyzer(
    private val onResult: (corners: List<PointF>?, frameAspect: Float) -> Unit,
) : ImageAnalysis.Analyzer {

    @Volatile
    private var lastRun = 0L

    override fun analyze(image: ImageProxy) {
        val now = System.currentTimeMillis()
        if (now - lastRun < THROTTLE_MS) {
            image.close()
            return
        }
        lastRun = now
        val result = try {
            detect(image)
        } catch (e: Throwable) {
            android.util.Log.w("DocAnalyzer", "detect failed", e)
            null
        }
        image.close()
        if (result != null) onResult(result.first, result.second)
    }

    private fun detect(image: ImageProxy): Pair<List<PointF>?, Float> {
        // The Y plane of the YUV frame is already a grayscale image.
        val plane = image.planes[0]
        val rowStride = plane.rowStride
        val buffer = plane.buffer
        val out = ByteArray(image.width * image.height)
        for (row in 0 until image.height) {
            buffer.position(row * rowStride)
            buffer.get(out, row * image.width, image.width)
        }
        val gray = Mat(image.height, image.width, CvType.CV_8UC1)
        gray.put(0, 0, out)

        // Rotate the sensor-oriented frame to match how the preview is displayed.
        when (image.imageInfo.rotationDegrees) {
            90 -> Core.rotate(gray, gray, Core.ROTATE_90_CLOCKWISE)
            180 -> Core.rotate(gray, gray, Core.ROTATE_180)
            270 -> Core.rotate(gray, gray, Core.ROTATE_90_COUNTERCLOCKWISE)
        }
        val aspect = gray.cols().toFloat() / gray.rows()
        return EdgeDetector.detectFromGray(gray) to aspect // detectFromGray releases gray
    }

    companion object {
        private const val THROTTLE_MS = 150L
    }
}
