package com.example.livingai.pages.camera

import android.graphics.Bitmap
import android.graphics.Matrix
import android.graphics.RectF
import android.util.Size
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import com.example.livingai.domain.camera.*
import com.example.livingai.domain.model.camera.*
import com.example.livingai.domain.usecases.AppDataUseCases
import com.example.livingai.utils.TiltSensorManager
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch

class CameraViewModel(
    private val orientationChecker: OrientationChecker,
    private val tiltChecker: TiltChecker,
    private val objectDetector: ObjectDetector,
    private val poseAnalyzer: PoseAnalyzer,
    private val captureHandler: CaptureHandler,
    private val measurementCalculator: MeasurementCalculator,
    private val tiltSensorManager: TiltSensorManager,
    private val appDataUseCases: AppDataUseCases
) : ViewModel() {

    private val _uiState = MutableStateFlow(CameraUiState())
    val uiState: StateFlow<CameraUiState> = _uiState.asStateFlow()
    private val tilt = tiltSensorManager.tilt

    private var frameCounter = 0
    private val frameSkipInterval = 5
    private var isAutoCaptureOn = false

    init {
        tiltSensorManager.start()
        observeSettings()
    }

    private fun observeSettings() {
        appDataUseCases.getSettings().onEach { 
            isAutoCaptureOn = it.isAutoCaptureOn
            _uiState.value = _uiState.value.copy(isAutoCaptureOn = it.isAutoCaptureOn)
        }.launchIn(viewModelScope)
    }

    override fun onCleared() {
        super.onCleared()
        tiltSensorManager.stop()
    }

    fun setRequiredOrientation(orientation: String) {
        val required = when (orientation.lowercase()) {
            "front", "back" -> CameraOrientation.PORTRAIT
            else -> CameraOrientation.LANDSCAPE
        }
        _uiState.value = _uiState.value.copy(
            requiredOrientation = required,
            targetOrientation = orientation
        )
    }

    fun processFrame(
        image: Bitmap, 
        deviceOrientation: Int,
        screenWidth: Float,
        screenHeight: Float
    ) {
        frameCounter = (frameCounter + 1) % frameSkipInterval
        if (frameCounter != 0) return

        viewModelScope.launch {
            val currentTilt = tilt.value
            val currentAnalysisSize = Size(image.width, image.height)
            
            val input = PipelineInput(
                image = image,
                deviceOrientation = deviceOrientation,
                deviceRoll = currentTilt.second,
                devicePitch = currentTilt.first,
                deviceAzimuth = currentTilt.third,
                requiredOrientation = _uiState.value.requiredOrientation,
                screenWidthPx = screenWidth,
                screenHeightPx = screenHeight,
                targetAnimal = "Cow", // Assuming Cow for now, can be parameter later
                orientation = _uiState.value.targetOrientation,
                previousDetectionResult = _uiState.value.lastDetectionResult
            )

            // Step 1: Check Orientation
            val orientationInstruction = orientationChecker.analyze(input)
            if (!orientationInstruction.isValid) {
                updateState(orientationInstruction, analysisSize = currentAnalysisSize)
                return@launch
            }

            // Step 2: Check Tilt
            val tiltInstruction = tiltChecker.analyze(input)
            if (!tiltInstruction.isValid) {
                updateState(tiltInstruction, analysisSize = currentAnalysisSize)
                return@launch
            }

            // Step 3: Detect Objects
            val detectionInstruction = objectDetector.analyze(input)
            if (!detectionInstruction.isValid) {
                updateState(detectionInstruction, analysisSize = currentAnalysisSize)
                return@launch
            }

            // Step 4: Check Pose (Silhouette matching)
            val poseInstruction = poseAnalyzer.analyze(input.copy(previousDetectionResult = detectionInstruction.result as? DetectionResult))
            if (!poseInstruction.isValid) {
                updateState(poseInstruction, detectionInstruction.result as? DetectionResult, analysisSize = currentAnalysisSize)
                return@launch
            }
            
            // All checks passed
            val currentState = _uiState.value
            _uiState.value = currentState.copy(
                currentInstruction = Instruction("Ready to capture", isValid = true),
                isReadyToCapture = true,
                lastDetectionResult = detectionInstruction.result as? DetectionResult,
                analysisSize = currentAnalysisSize,
                shouldCapture = isAutoCaptureOn && !currentState.isPreviewMode && !currentState.shouldCapture
            )
        }
    }

    private fun updateState(instruction: Instruction, latestDetectionResult: DetectionResult? = null, analysisSize: Size? = null) {
        val detectionResult = (instruction.result as? DetectionResult) ?: latestDetectionResult
        _uiState.value = _uiState.value.copy(
            currentInstruction = instruction,
            isReadyToCapture = false,
            lastDetectionResult = detectionResult ?: _uiState.value.lastDetectionResult,
            analysisSize = analysisSize ?: _uiState.value.analysisSize,
            shouldCapture = false
        )
    }
    
    fun onCaptureTriggered() {
        _uiState.value = _uiState.value.copy(shouldCapture = false)
    }
    
    fun onCaptureClicked(
        image: Bitmap, 
        deviceOrientation: Int,
        screenWidth: Float,
        screenHeight: Float
    ) {
        viewModelScope.launch {
            val detectionResult = _uiState.value.lastDetectionResult ?: return@launch
            val analysisSize = _uiState.value.analysisSize
            val currentTilt = tilt.value
            
            // Scale detection result to match capture image resolution
            val scaledDetectionResult = if (analysisSize != null) {
                val scaleX = image.width.toFloat() / analysisSize.width
                val scaleY = image.height.toFloat() / analysisSize.height
                val matrix = Matrix()
                matrix.postScale(scaleX, scaleY)
                
                val scaledBounds = detectionResult.animalBounds?.let { 
                    val r = RectF(it)
                    matrix.mapRect(r)
                    r
                }
                
                val scaledRefs = detectionResult.referenceObjects.map { ref ->
                    val r = RectF(ref.bounds)
                    matrix.mapRect(r)
                    ref.copy(bounds = r)
                }
                
                detectionResult.copy(
                    animalBounds = scaledBounds,
                    referenceObjects = scaledRefs
                )
            } else {
                detectionResult
            }
            
             val input = PipelineInput(
                image = image,
                deviceOrientation = deviceOrientation,
                deviceRoll = currentTilt.second,
                devicePitch = currentTilt.first,
                deviceAzimuth = currentTilt.third,
                requiredOrientation = _uiState.value.requiredOrientation,
                screenWidthPx = screenWidth,
                screenHeightPx = screenHeight,
                targetAnimal = "Cow",
                orientation = _uiState.value.targetOrientation
            )

            val captureData = captureHandler.capture(input, scaledDetectionResult)
            
            _uiState.value = _uiState.value.copy(
                captureData = captureData,
                isPreviewMode = true
            )
        }
    }

    fun onReferenceObjectSelected(refObj: ReferenceObject, realHeight: Float) {
        val captureData = _uiState.value.captureData ?: return
        
        val realMetrics = measurementCalculator.calculateRealMetrics(
            targetHeight = realHeight,
            referenceObject = refObj,
            currentMetrics = captureData.animalMetrics
        )
        
        _uiState.value = _uiState.value.copy(
            realWorldMetrics = realMetrics
        )
    }
    
    fun resetCamera() {
        _uiState.value = _uiState.value.copy(
            isPreviewMode = false,
            captureData = null,
            realWorldMetrics = null,
            isReadyToCapture = false,
            currentInstruction = null,
            shouldCapture = false
        )
    }
}


data class CameraUiState(
    val requiredOrientation: CameraOrientation = CameraOrientation.LANDSCAPE,
    val targetOrientation: String = "side",
    val currentInstruction: Instruction? = null,
    val isReadyToCapture: Boolean = false,
    val lastDetectionResult: DetectionResult? = null,
    val analysisSize: Size? = null,
    val isPreviewMode: Boolean = false,
    val captureData: CaptureData? = null,
    val realWorldMetrics: RealWorldMetrics? = null,
    val shouldCapture: Boolean = false,
    val isAutoCaptureOn: Boolean = false
)
