package com.example.godeye.managers

import android.annotation.SuppressLint
import android.content.Context
import android.graphics.SurfaceTexture
import android.hardware.camera2.*
import android.util.Size
import android.view.Surface
import com.example.godeye.models.AppError
import com.example.godeye.models.CameraInfo
import com.example.godeye.models.CameraState
import com.example.godeye.utils.Logger
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import java.util.concurrent.Semaphore
import java.util.concurrent.TimeUnit

/**
 * Camera2Manager - управление камерами устройства с использованием Camera2 API
 * Соответствует требованиям ТЗ для работы с различными типами камер
 */
class Camera2Manager(private val context: Context) {

    private val cameraManager = context.getSystemService(Context.CAMERA_SERVICE) as CameraManager
    private var cameraDevice: CameraDevice? = null
    private var captureSession: CameraCaptureSession? = null
    private var currentCameraId: String? = null
    private val cameraOpenCloseLock = Semaphore(1)

    private val _cameraState = MutableStateFlow(CameraState.CLOSED)
    val cameraState: StateFlow<CameraState> = _cameraState.asStateFlow()

    private val _availableCameras = MutableStateFlow<List<CameraInfo>>(emptyList())
    val availableCameras: StateFlow<List<CameraInfo>> = _availableCameras.asStateFlow()

    init {
        detectAvailableCameras()
    }

    /**
     * Определение доступных камер устройства согласно ТЗ
     * Поддерживает: back, front, wide, telephoto
     */
    private fun detectAvailableCameras() {
        Logger.step("CAMERA_DETECTION", "Detecting available cameras")

        val cameras = mutableListOf<CameraInfo>()

        try {
            for (cameraId in cameraManager.cameraIdList) {
                val characteristics = cameraManager.getCameraCharacteristics(cameraId)
                val facing = characteristics.get(CameraCharacteristics.LENS_FACING)
                val focalLengths = characteristics.get(CameraCharacteristics.LENS_INFO_AVAILABLE_FOCAL_LENGTHS)

                val cameraType = when (facing) {
                    CameraCharacteristics.LENS_FACING_BACK -> {
                        // Определяем тип задней камеры по фокусному расстоянию
                        when {
                            focalLengths != null && focalLengths.size > 1 -> {
                                if (focalLengths.minOrNull()!! < 3.0f) "ultra_wide"
                                else if (focalLengths.maxOrNull()!! > 6.0f) "telephoto"
                                else "back"
                            }
                            else -> "back"
                        }
                    }
                    CameraCharacteristics.LENS_FACING_FRONT -> "front"
                    else -> "unknown"
                }

                if (cameraType != "unknown") {
                    val configMap = characteristics.get(CameraCharacteristics.SCALER_STREAM_CONFIGURATION_MAP)
                    val sizes = configMap?.getOutputSizes(SurfaceTexture::class.java) ?: emptyArray()

                    cameras.add(
                        CameraInfo(
                            id = cameraId,
                            type = cameraType,
                            facing = facing ?: -1,
                            supportedSizes = sizes.toList(),
                            focalLengths = focalLengths?.toList() ?: emptyList()
                        )
                    )

                    Logger.d("Camera detected: $cameraId, type: $cameraType, sizes: ${sizes.size}")
                }
            }

            _availableCameras.value = cameras
            Logger.step("CAMERA_DETECTION_COMPLETE", "Found ${cameras.size} cameras: ${cameras.map { it.type }}")

        } catch (e: CameraAccessException) {
            Logger.error("CAMERA_DETECTION_ERROR", "Failed to detect cameras", e)
        }
    }

    /**
     * Получение списка доступных типов камер для регистрации на сервере
     */
    fun getAvailableCameraTypes(): List<String> {
        return _availableCameras.value.map { it.type }.distinct()
    }

    /**
     * Запуск камеры указанного типа
     */
    @SuppressLint("MissingPermission")
    fun startCamera(cameraType: String, surface: Surface, onError: (AppError) -> Unit) {
        Logger.step("CAMERA_START", "Starting camera: $cameraType")

        val cameraInfo = _availableCameras.value.find { it.type == cameraType }
        if (cameraInfo == null) {
            Logger.error("CAMERA_NOT_FOUND", "Camera type not available: $cameraType", null)
            onError(AppError.CameraNotAvailable)
            return
        }

        try {
            if (!cameraOpenCloseLock.tryAcquire(2500, TimeUnit.MILLISECONDS)) {
                Logger.error("CAMERA_LOCK_TIMEOUT", "Camera lock timeout", null)
                onError(AppError.CameraNotAvailable)
                return
            }

            _cameraState.value = CameraState.OPENING

            val stateCallback = object : CameraDevice.StateCallback() {
                override fun onOpened(camera: CameraDevice) {
                    Logger.step("CAMERA_OPENED", "Camera opened: ${camera.id}")
                    cameraOpenCloseLock.release()
                    cameraDevice = camera
                    currentCameraId = camera.id
                    _cameraState.value = CameraState.OPENED
                    createCaptureSession(surface, onError)
                }

                override fun onDisconnected(camera: CameraDevice) {
                    Logger.step("CAMERA_DISCONNECTED", "Camera disconnected: ${camera.id}")
                    cameraOpenCloseLock.release()
                    camera.close()
                    cameraDevice = null
                    currentCameraId = null
                    _cameraState.value = CameraState.CLOSED
                }

                override fun onError(camera: CameraDevice, error: Int) {
                    Logger.error("CAMERA_ERROR", "Camera error: $error for ${camera.id}", null)
                    cameraOpenCloseLock.release()
                    camera.close()
                    cameraDevice = null
                    currentCameraId = null
                    _cameraState.value = CameraState.ERROR
                    onError(AppError.CameraNotAvailable)
                }
            }

            cameraManager.openCamera(cameraInfo.id, stateCallback, null)

        } catch (e: CameraAccessException) {
            Logger.error("CAMERA_START_ERROR", "Failed to start camera", e)
            onError(AppError.CameraNotAvailable)
        } catch (e: SecurityException) {
            Logger.error("CAMERA_PERMISSION_ERROR", "Camera permission denied", e)
            onError(AppError.CameraPermissionDenied)
        }
    }

    /**
     * Создание сессии захвата для передачи видео
     */
    private fun createCaptureSession(surface: Surface, onError: (AppError) -> Unit) {
        try {
            val camera = cameraDevice ?: run {
                onError(AppError.CameraNotAvailable)
                return
            }

            _cameraState.value = CameraState.CONFIGURING

            val sessionCallback = object : CameraCaptureSession.StateCallback() {
                override fun onConfigured(session: CameraCaptureSession) {
                    Logger.step("CAPTURE_SESSION_CONFIGURED", "Capture session configured")
                    captureSession = session
                    _cameraState.value = CameraState.ACTIVE
                    startPreview(session, surface, onError)
                }

                override fun onConfigureFailed(session: CameraCaptureSession) {
                    Logger.error("CAPTURE_SESSION_FAILED", "Failed to configure capture session", null)
                    _cameraState.value = CameraState.ERROR
                    onError(AppError.CameraNotAvailable)
                }
            }

            // Используем стандартный метод createCaptureSession вместо устаревшего
            camera.createCaptureSession(listOf(surface), sessionCallback, null)

        } catch (e: CameraAccessException) {
            Logger.error("CAPTURE_SESSION_ERROR", "Failed to create capture session", e)
            onError(AppError.CameraNotAvailable)
        }
    }

    /**
     * Запуск предварительного просмотра
     */
    private fun startPreview(session: CameraCaptureSession, surface: Surface, onError: (AppError) -> Unit) {
        try {
            val camera = cameraDevice ?: run {
                onError(AppError.CameraNotAvailable)
                return
            }

            val previewRequestBuilder = camera.createCaptureRequest(CameraDevice.TEMPLATE_PREVIEW)
            previewRequestBuilder.addTarget(surface)

            // Настройки для оптимального качества видео
            previewRequestBuilder.set(CaptureRequest.CONTROL_MODE, CaptureRequest.CONTROL_MODE_AUTO)
            previewRequestBuilder.set(CaptureRequest.CONTROL_AF_MODE, CaptureRequest.CONTROL_AF_MODE_CONTINUOUS_VIDEO)
            previewRequestBuilder.set(CaptureRequest.CONTROL_AE_MODE, CaptureRequest.CONTROL_AE_MODE_ON)

            val previewRequest = previewRequestBuilder.build()

            session.setRepeatingRequest(previewRequest, object : CameraCaptureSession.CaptureCallback() {
                override fun onCaptureStarted(
                    session: CameraCaptureSession,
                    request: CaptureRequest,
                    timestamp: Long,
                    frameNumber: Long
                ) {
                    // Preview started
                }
            }, null)

            Logger.step("CAMERA_PREVIEW_STARTED", "Camera preview started")

        } catch (e: CameraAccessException) {
            Logger.error("CAMERA_PREVIEW_ERROR", "Failed to start preview", e)
            onError(AppError.CameraNotAvailable)
        }
    }

    /**
     * Переключение на другую камеру
     */
    fun switchCamera(newCameraType: String, surface: Surface, onError: (AppError) -> Unit) {
        Logger.step("CAMERA_SWITCH", "Switching camera to: $newCameraType")

        stopCamera()
        startCamera(newCameraType, surface, onError)
    }

    /**
     * Остановка камеры
     */
    fun stopCamera() {
        Logger.step("CAMERA_STOP", "Stopping camera")

        try {
            cameraOpenCloseLock.acquire()

            captureSession?.close()
            captureSession = null

            cameraDevice?.close()
            cameraDevice = null
            currentCameraId = null

            _cameraState.value = CameraState.CLOSED

            Logger.step("CAMERA_STOPPED", "Camera stopped")

        } catch (e: InterruptedException) {
            Logger.error("CAMERA_STOP_ERROR", "Interrupted while stopping camera", e)
        } finally {
            cameraOpenCloseLock.release()
        }
    }

    /**
     * Получение оптимального размера для WebRTC
     */
    fun getOptimalSize(cameraType: String, maxWidth: Int = 1920, maxHeight: Int = 1080): Size? {
        val cameraInfo = _availableCameras.value.find { it.type == cameraType } ?: return null

        return cameraInfo.supportedSizes
            .filter { it.width <= maxWidth && it.height <= maxHeight }
            .maxByOrNull { it.width * it.height }
    }

    /**
     * Получение текущего состояния камеры
     */
    fun getCurrentCameraType(): String? {
        val cameraId = currentCameraId ?: return null
        return _availableCameras.value.find { it.id == cameraId }?.type
    }

    fun release() {
        Logger.step("CAMERA_MANAGER_RELEASE", "Releasing Camera2Manager")
        stopCamera()
    }
}
