package com.example.livingai.domain.ml

import android.content.Context
import android.graphics.Rect
import android.hardware.camera2.CameraCharacteristics
import android.hardware.camera2.CameraManager
import android.util.Size
import android.util.SizeF

/**
 * Utility to read camera intrinsics from Camera2 and compute focal length (pixels).
 *
 * Usage:
 *  val (fPx, imgW, imgH) = CameraIntrinsicsFetcher.fetch(context, cameraId, imageSize)
 *  CameraInfoProvider.init(CameraInfoData(fPx, imgW, imgH, px, py, ...))
 *
 * imageSize = the resolution you will actually receive from the ImageReader / CameraX output (width,height)
 *
 * Formula:
 *   f_px = f_mm / sensorWidth_mm * imageWidth_px
 *
 * More accurate: use activeArray size mapping to sensor physical size if needed.
 */
object CameraIntrinsicsFetcher {

    data class Result(
        val focalLengthPixels: Float,
        val imageWidthPx: Int,
        val imageHeightPx: Int,
        val principalPointX: Float,
        val principalPointY: Float,
        val sensorPhysicalSizeMm: SizeF?
    )

    /**
     * cameraId = device camera id (get from CameraManager)
     * imageSize = the actual output image size you will capture (e.g., 1920x1080)
     */
    fun fetch(context: Context, cameraId: String, imageSize: Size): Result {
        val mgr = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
        val characteristics = mgr.getCameraCharacteristics(cameraId)

        val focalLengths = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)
        val fMm = when {
            focalLengths != null && focalLengths.isNotEmpty() -> focalLengths[0]  // mm
            else -> 4.0f
        }

        val sensorSize = characteristics.get(CameraCharacteristics.SENSOR_INFO_PHYSICAL_SIZE) // in mm
        val sensorSizeMm = sensorSize

        // active array size gives pixel array cropping of sensor -> map principal point
        val activeRect = characteristics.get(CameraCharacteristics.SENSOR_INFO_ACTIVE_ARRAY_SIZE) // Rect
        val activeRectW = activeRect?.width() ?: imageSize.width
        val activeRectH = activeRect?.height() ?: imageSize.height

        // Compute focal in pixels: ratio f_mm / sensorWidth_mm * imageWidth_px
        val fPx = if (sensorSizeMm != null && sensorSizeMm.width > 0f) {
            (fMm / sensorSizeMm.width) * imageSize.width
        } else {
            // fallback: estimate based on sensor pixel array
            (fMm / 4.0f) * imageSize.width
        }

        val principalX = (activeRect?.centerX() ?: imageSize.width / 2).toFloat()
        val principalY = (activeRect?.centerY() ?: imageSize.height / 2).toFloat()

        return Result(
            focalLengthPixels = fPx,
            imageWidthPx = imageSize.width,
            imageHeightPx = imageSize.height,
            principalPointX = principalX,
            principalPointY = principalY,
            sensorPhysicalSizeMm = sensorSizeMm
        )
    }
}
