package com.example.livingai.domain.ml

import android.graphics.Bitmap
import android.graphics.Rect
import com.example.livingai.utils.TiltSensorManager

object FrameMetadataProvider {

    lateinit var aiModel: AIModel  // injected once from AppModule
    var tiltSensorManager: TiltSensorManager? = null
    
    // External data sources
    var latestDepthResult: DepthResult? = null
    var deviceRotation: Int = 0

    suspend fun getSegmentation(bitmap: Bitmap): SegmentationResult? {
        return try {
            val (maskBitmap, booleanMask, bbox) = aiModel.segmentImage(bitmap) ?: return null
            SegmentationResult(maskBitmap, booleanMask, bbox)
        } catch (_: Exception) {
            null
        }
    }

    data class SegmentationResult(
        val maskBitmap: Bitmap?,
        val mask: BooleanArray,
        val boundingBox: Rect
    ) {
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as SegmentationResult

            if (maskBitmap != other.maskBitmap) return false
            if (!mask.contentEquals(other.mask)) return false
            if (boundingBox != other.boundingBox) return false

            return true
        }

        override fun hashCode(): Int {
            var result = maskBitmap?.hashCode() ?: 0
            result = 31 * result + mask.contentHashCode()
            result = 31 * result + boundingBox.hashCode()
            return result
        }
    }

    fun getDepthData(): DepthResult {
        return latestDepthResult ?: DepthResult(null, 0, 0, null)
    }

    data class DepthResult(
        val depthMeters: FloatArray?,
        val width: Int,
        val height: Int,
        val confidence: FloatArray?
    ) {
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as DepthResult

            if (depthMeters != null) {
                if (other.depthMeters == null) return false
                if (!depthMeters.contentEquals(other.depthMeters)) return false
            } else if (other.depthMeters != null) return false
            if (width != other.width) return false
            if (height != other.height) return false
            if (confidence != null) {
                if (other.confidence == null) return false
                if (!confidence.contentEquals(other.confidence)) return false
            } else if (other.confidence != null) return false

            return true
        }

        override fun hashCode(): Int {
            var result = depthMeters?.contentHashCode() ?: 0
            result = 31 * result + width
            result = 31 * result + height
            result = 31 * result + (confidence?.contentHashCode() ?: 0)
            return result
        }
    }

    fun getIMU(): IMUResult {
        val (pitch, roll, yaw) = tiltSensorManager?.tilt?.value ?: Triple(0f, 0f, 0f)
        return IMUResult(pitch, roll, yaw)
    }

    data class IMUResult(val pitch: Float, val roll: Float, val yaw: Float)

    fun getRotation(): Int {
        return deviceRotation
    }

    data class FrameCollectedMetadata(
        val segmentationMaskBitmap: Bitmap?,
        val segmentationBox: Rect?,
        val depthMeters: FloatArray?,
        val depthWidth: Int,
        val depthHeight: Int,
        val depthConfidence: FloatArray?,
        val pitch: Float,
        val roll: Float,
        val yaw: Float,
        val rotationDegrees: Int
    ) {
        override fun equals(other: Any?): Boolean {
            if (this === other) return true
            if (javaClass != other?.javaClass) return false

            other as FrameCollectedMetadata

            if (segmentationMaskBitmap != other.segmentationMaskBitmap) return false
            if (segmentationBox != other.segmentationBox) return false
            if (depthMeters != null) {
                if (other.depthMeters == null) return false
                if (!depthMeters.contentEquals(other.depthMeters)) return false
            } else if (other.depthMeters != null) return false
            if (depthWidth != other.depthWidth) return false
            if (depthHeight != other.depthHeight) return false
            if (depthConfidence != null) {
                if (other.depthConfidence == null) return false
                if (!depthConfidence.contentEquals(other.depthConfidence)) return false
            } else if (other.depthConfidence != null) return false
            if (pitch != other.pitch) return false
            if (roll != other.roll) return false
            if (yaw != other.yaw) return false
            if (rotationDegrees != other.rotationDegrees) return false

            return true
        }

        override fun hashCode(): Int {
            var result = segmentationMaskBitmap?.hashCode() ?: 0
            result = 31 * result + (segmentationBox?.hashCode() ?: 0)
            result = 31 * result + (depthMeters?.contentHashCode() ?: 0)
            result = 31 * result + depthWidth
            result = 31 * result + depthHeight
            result = 31 * result + (depthConfidence?.contentHashCode() ?: 0)
            result = 31 * result + pitch.hashCode()
            result = 31 * result + roll.hashCode()
            result = 31 * result + yaw.hashCode()
            result = 31 * result + rotationDegrees
            return result
        }
    }

    suspend fun collectMetadata(bitmap: Bitmap): FrameCollectedMetadata {
        val seg = getSegmentation(bitmap)
        val depth = getDepthData()
        val imu = getIMU()
        val rot = getRotation()

        return FrameCollectedMetadata(
            segmentationMaskBitmap = seg?.maskBitmap,
            segmentationBox = seg?.boundingBox,
            depthMeters = depth.depthMeters,
            depthWidth = depth.width,
            depthHeight = depth.height,
            depthConfidence = depth.confidence,
            pitch = imu.pitch,
            roll = imu.roll,
            yaw = imu.yaw,
            rotationDegrees = rot
        )
    }

    fun FrameCollectedMetadata.toFrameData(bitmap: Bitmap): FrameData {
        return FrameData(
            imageBitmap = bitmap,
            segmentationBox = segmentationBox,
            segmentationMaskBitmap = segmentationMaskBitmap,
            depthMapMeters = depthMeters,
            depthWidth = depthWidth,
            depthHeight = depthHeight,
            depthConfidence = depthConfidence,
            imuPitchDegrees = pitch,
            imuRollDegrees = roll,
            imuYawDegrees = yaw,
            cameraRotationDegrees = rotationDegrees,
            
            // New fields populated from bitmap if available or passed down
            imageWidth = bitmap.width,
            imageHeight = bitmap.height,
            medianDepth = null // Can calculate median from depthMeters if needed
        )
    }
}
