package com.nexlab.openclaw.node.service

import android.Manifest
import android.content.Context
import android.content.pm.PackageManager
import android.graphics.ImageFormat
import android.hardware.camera2.*
import android.media.Image
import android.media.ImageReader
import android.media.MediaRecorder
import android.os.Handler
import android.os.HandlerThread
import android.util.Base64
import android.util.Size
import android.view.Surface
import androidx.core.content.ContextCompat
import dagger.hilt.android.qualifiers.ApplicationContext
import kotlinx.coroutines.suspendCancellableCoroutine
import java.io.ByteArrayOutputStream
import java.io.File
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.coroutines.resume
import kotlin.coroutines.resumeWithException

/**
 * Service for camera operations: photo capture and video recording
 */
@Singleton
class CameraService @Inject constructor(
    @ApplicationContext private val context: Context,
    private val permissionManager: PermissionManager
) {
    private var cameraDevice: CameraDevice? = null
    private var captureSession: CameraCaptureSession? = null
    private var imageReader: ImageReader? = null
    private var mediaRecorder: MediaRecorder? = null
    private var backgroundHandler: Handler? = null
    private var backgroundThread: HandlerThread? = null
    private var isRecording = false

    private val cameraManager: CameraManager = 
        context.getSystemService(Context.CAMERA_SERVICE) as CameraManager

    /**
     * Check if camera permission is granted
     */
    fun hasCameraPermission(): Boolean {
        return ContextCompat.checkSelfPermission(
            context, Manifest.permission.CAMERA
        ) == PackageManager.PERMISSION_GRANTED
    }

    /**
     * Get list of available cameras
     */
    fun getCameras(): List<CameraInfo> {
        return cameraManager.cameraIdList.map { id ->
            val characteristics = cameraManager.getCameraCharacteristics(id)
            val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
            CameraInfo(
                id = id,
                facing = when (facing) {
                    CameraCharacteristics.LENS_FACING_FRONT -> "front"
                    CameraCharacteristics.LENS_FACING_BACK -> "back"
                    else -> "external"
                }
            )
        }
    }

    /**
     * Capture a photo and return as base64
     */
    suspend fun capturePhoto(
        cameraId: String = "0",
        quality: Int = 85
    ): Result<String> = suspendCancellableCoroutine { continuation ->
        try {
            startBackgroundThread()

            if (!hasCameraPermission()) {
                continuation.resume(Result.failure(SecurityException("Camera permission not granted")))
                return@suspendCancellableCoroutine
            }

            val characteristics = cameraManager.getCameraCharacteristics(cameraId)
            val map = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
            val size = map?.getOutputSizes(ImageFormat.JPEG)?.maxByOrNull { it.width * it.height }
                ?: Size(1920, 1080)

            imageReader = ImageReader.newInstance(
                size.width, size.height,
                ImageFormat.JPEG, 2
            )

            imageReader?.setOnImageAvailableListener({ reader ->
                val image = reader.acquireLatestImage()
                if (image != null) {
                    val buffer = image.planes[0].buffer
                    val bytes = ByteArray(buffer.remaining())
                    buffer.get(bytes)
                    
                    val outputStream = ByteArrayOutputStream()
                    outputStream.write(bytes)
                    val base64 = Base64.encodeToString(bytes, Base64.NO_WRAP)
                    
                    image.close()
                    continuation.resume(Result.success(base64))
                }
            }, backgroundHandler)

            cameraManager.openCamera(cameraId, object : CameraDevice.StateCallback() {
                override fun onOpened(camera: CameraDevice) {
                    cameraDevice = camera
                    createCaptureSession()
                }

                override fun onDisconnected(camera: CameraDevice) {
                    camera.close()
                    cameraDevice = null
                }

                override fun onError(camera: CameraDevice, error: Int) {
                    camera.close()
                    cameraDevice = null
                    continuation.resume(Result.failure(Exception("Camera error: $error")))
                }
            }, backgroundHandler)

            continuation.invokeOnCancellation {
                stopCapture()
            }

        } catch (e: Exception) {
            continuation.resume(Result.failure(e))
        }
    }

    private fun createCaptureSession() {
        val surface = imageReader?.surface ?: return
        val camera = cameraDevice ?: return

        try {
            camera.createCaptureSession(
                listOf(surface),
                object : CameraCaptureSession.StateCallback() {
                    override fun onConfigured(session: CameraCaptureSession) {
                        captureSession = session
                        capturePhotoRequest()
                    }

                    override fun onConfigureFailed(session: CameraCaptureSession) {
                        // Handle failure
                    }
                },
                backgroundHandler
            )
        } catch (e: Exception) {
            // Handle exception
        }
    }

    private fun capturePhotoRequest() {
        val camera = cameraDevice ?: return
        val surface = imageReader?.surface ?: return

        try {
            val captureRequest = camera.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE)
            captureRequest.addTarget(surface)
            captureRequest.set(CaptureRequest.JPEG_QUALITY, 85.toByte())

            captureSession?.capture(
                captureRequest.build(),
                object : CameraCaptureSession.CaptureCallback() {},
                backgroundHandler
            )
        } catch (e: Exception) {
            // Handle exception
        }
    }

    /**
     * Start video recording
     */
    @Suppress("MissingPermission")
    fun startRecording(
        outputFile: File,
        cameraId: String = "0",
        onError: (Exception) -> Unit = {}
    ): Boolean {
        if (!hasCameraPermission()) {
            onError(SecurityException("Camera permission not granted"))
            return false
        }

        if (isRecording) return false

        try {
            mediaRecorder = MediaRecorder().apply {
                setAudioSource(MediaRecorder.AudioSource.MIC)
                setVideoSource(MediaRecorder.VideoSource.SURFACE)
                setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
                setOutputFile(outputFile.absolutePath)
                setVideoEncoder(MediaRecorder.VideoEncoder.H264)
                setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
                prepare()
                start()
            }
            isRecording = true
            return true
        } catch (e: Exception) {
            onError(e)
            return false
        }
    }

    /**
     * Stop video recording
     */
    fun stopRecording(): File? {
        if (!isRecording) return null

        return try {
            mediaRecorder?.apply {
                stop()
                reset()
                release()
            }
            mediaRecorder = null
            isRecording = false
            null // Return the file path
        } catch (e: Exception) {
            mediaRecorder?.release()
            mediaRecorder = null
            isRecording = false
            null
        }
    }

    private fun startBackgroundThread() {
        backgroundThread = HandlerThread("CameraBackground").also { it.start() }
        backgroundHandler = Handler(backgroundThread!!.looper)
    }

    private fun stopBackgroundThread() {
        backgroundThread?.quitSafely()
        try {
            backgroundThread?.join()
            backgroundThread = null
            backgroundHandler = null
        } catch (e: InterruptedException) {
            // Handle
        }
    }

    fun stopCapture() {
        captureSession?.close()
        captureSession = null
        cameraDevice?.close()
        cameraDevice = null
        imageReader?.close()
        imageReader = null
        stopBackgroundThread()
    }

    data class CameraInfo(
        val id: String,
        val facing: String  // "front", "back", "external"
    )
}
