package com.example.livingai.domain.ml

import android.graphics.RectF
import android.util.Log
import com.example.livingai.utils.Constants
import kotlin.math.abs
import kotlin.math.max
import kotlin.math.sin

// ------------------------------------------------------------
//  CONFIG CLASS
// ------------------------------------------------------------
data class AnalyzerThresholds(
    val toleranceRatio: Float = 0.02f,

    // Height estimation
    val minTargetHeightMeters: Float = 0.60f,
    val maxTargetHeightMeters: Float = 0.70f,

    // Real physical height of subject
    val subjectRealHeightMeters: Float = 1.55f
)

// ------------------------------------------------------------
//  STATES
// ------------------------------------------------------------
sealed class FeedbackState(val message: String) {
    object Idle : FeedbackState("")
    object Searching : FeedbackState("Searching for subject...")
    object TooFar : FeedbackState("Move closer")
    object TooClose : FeedbackState("Move back")
    object TooLow : FeedbackState("Raise phone")
    object TooHigh : FeedbackState("Lower phone")
    object PhoneTooLow : FeedbackState("Raise phone to 60 to 70 cm from ground")
    object PhoneTooHigh : FeedbackState("Lower phone to 60 to 70 cm from ground")
    object Optimal : FeedbackState("Hold still")
}

// ------------------------------------------------------------
//  ANALYZER INTERFACE
// ------------------------------------------------------------
interface FeedbackAnalyzer {
    fun analyze(
        detection: ObjectDetector.DetectionResult?,
        frameWidth: Int,
        frameHeight: Int,
        screenHeight: Int,
        tiltDegrees: Float,
        focalLengthPx: Float
    ): FeedbackState
}

// ------------------------------------------------------------
//  IMPLEMENTATION
// ------------------------------------------------------------
class FeedbackAnalyzerImpl(
    private val thresholds: AnalyzerThresholds
) : FeedbackAnalyzer {

    override fun analyze(
        detection: ObjectDetector.DetectionResult?,
        frameWidth: Int,
        frameHeight: Int,
        screenHeight: Int,
        tiltDegrees: Float,
        focalLengthPx: Float
    ): FeedbackState {

        if (detection == null) return FeedbackState.Searching
        if (frameWidth <= 0 || frameHeight <= 0) return FeedbackState.Idle

        val pc = Precomputed(
            detection.boundingBox,
            frameWidth,
            frameHeight,
            screenHeight,
            thresholds
        )

        val cameraHeight = estimateCameraHeight(pc.detectionHeight, tiltDegrees, focalLengthPx)
        Log.d("FeedbackAnalyzerImpl", "Camera Height: $cameraHeight")
        return when {
            // ORDER MATTERS — evaluate alignment first
            isTooHigh(pc) -> FeedbackState.TooHigh
            isTooLow(pc) -> FeedbackState.TooLow
            isTooClose(pc) -> FeedbackState.TooClose
            isTooFar(pc) -> FeedbackState.TooFar

            // Height estimation last
            isHeightTooLow(cameraHeight) -> FeedbackState.PhoneTooLow
            isHeightTooHigh(cameraHeight) -> FeedbackState.PhoneTooHigh

            else -> FeedbackState.Optimal
        }
    }

    private fun isTooLow(pc: Precomputed): Boolean =
        pc.isBottomInside && !pc.isTopInside && ((pc.frameTop - pc.detectionTop) > pc.tolerance)

    private fun isTooHigh(pc: Precomputed): Boolean =
        !pc.isBottomInside && pc.isTopInside && ((pc.detectionBottom - pc.frameBottom) > pc.tolerance)

    // OBJECT TOO CLOSE (bigger than allowed)
    private fun isTooClose(pc: Precomputed): Boolean =
        !pc.isTopInside && !pc.isBottomInside && ((pc.detectionHeight - pc.frameHeight) > pc.tolerance)

    // OBJECT TOO FAR (too small)
    private fun isTooFar(pc: Precomputed): Boolean =
        pc.isTopInside && pc.isBottomInside &&
                ((pc.frameHeight - pc.detectionHeight) > pc.tolerance)

    private fun isHeightTooLow(heightMeters: Float): Boolean =
        heightMeters > 0 &&
                (thresholds.minTargetHeightMeters > heightMeters)

    private fun isHeightTooHigh(heightMeters: Float): Boolean =
        heightMeters > (thresholds.maxTargetHeightMeters)

    private fun estimateCameraHeight(
        pixelHeight: Float,
        tiltDegrees: Float,
        focalLengthPx: Float
    ): Float {
        val tiltRad = Math.toRadians(tiltDegrees.toDouble())

        val realHeight = thresholds.subjectRealHeightMeters
        if (pixelHeight <= 0f || focalLengthPx <= 0f) return -1f

        val distance = (realHeight * focalLengthPx) / pixelHeight
        Log.d("FeedbackAnalyzerImpl", "Distance: $distance")
        return (distance * sin(tiltRad)).toFloat()
    }

    private data class Precomputed(
        val box: RectF,
        val frameWidth: Int,
        val frameHeight: Int,
        val screenHeight: Int,
        val t: AnalyzerThresholds
    ) {
        private val modelFrameHeight = Constants.MODEL_HEIGHT
        private val scaleSlip = ((screenHeight - modelFrameHeight) * screenHeight) / (2F * modelFrameHeight)
        val detectionTop = (box.top * screenHeight / modelFrameHeight) - scaleSlip
        val detectionBottom = (box.bottom * screenHeight / modelFrameHeight) - scaleSlip
        val detectionHeight = max(0f, detectionBottom - detectionTop)

        // Frame centered vertically
        val frameTop = (screenHeight - frameHeight) / 2f
        val frameBottom = frameTop + frameHeight

        val tolerance = t.toleranceRatio * screenHeight

        // Inside checks with tolerance
        val isTopInside = detectionTop >= frameTop
        val isBottomInside = detectionBottom <= frameBottom

    }
}
