package com.example.godeye.managers

import android.content.Context
import com.example.godeye.utils.Logger
import kotlinx.coroutines.*
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import io.socket.client.IO
import io.socket.client.Socket
import org.json.JSONObject
import java.net.URI

/**
 * Менеджер Socket.IO соединения с сервером
 */
class SocketManager(private val context: Context) {

    companion object {
        private const val TAG = "SocketManager"
    }

    // События подключения
    sealed class ConnectionEvent {
        object Connected : ConnectionEvent()
        object Disconnected : ConnectionEvent()
        data class Error(val message: String) : ConnectionEvent()
        data class CameraRequest(val sessionId: String, val operatorId: String, val message: String) : ConnectionEvent()
    }

    private val _events = MutableStateFlow<ConnectionEvent?>(null)
    val events: Flow<ConnectionEvent?> = _events

    private var socket: Socket? = null
    private var webRTCManager: WebRTCManager? = null
    private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())

    // ИСПРАВЛЕНИЕ: Добавляем флаг для предотвращения множественной регистрации
    private var isDeviceRegistered = false
    private var currentDeviceId: String? = null

    /**
     * Подключение к серверу
     */
    fun connect(serverUrl: String, webRTCManager: WebRTCManager) {
        try {
            this.webRTCManager = webRTCManager

            Logger.step("SOCKET_CONNECTING", "Connecting to server: $serverUrl")

            val options = IO.Options().apply {
                forceNew = true
                reconnection = true
                timeout = 10000
            }

            socket = IO.socket(URI.create(serverUrl), options)

            setupConnectionHandlers()
            setupCameraHandlers()
            setupWebRTCHandlers()
            setupWebRTCCallbacks()

            socket?.connect()

        } catch (e: Exception) {
            Logger.error("SOCKET_CONNECT_ERROR", "Failed to connect to server", e)
            _events.value = ConnectionEvent.Error("Ошибка подключения: ${e.message}")
        }
    }

    /**
     * Настройка основных обработчиков подключения
     */
    private fun setupConnectionHandlers() {
        socket?.on(Socket.EVENT_CONNECT) {
            Logger.step("SOCKET_CONNECTED", "Connected to server")
            _events.value = ConnectionEvent.Connected
        }

        socket?.on(Socket.EVENT_DISCONNECT) {
            Logger.step("SOCKET_DISCONNECTED", "Disconnected from server")
            _events.value = ConnectionEvent.Disconnected
        }

        socket?.on(Socket.EVENT_CONNECT_ERROR) { args ->
            val error = if (args.isNotEmpty()) args[0].toString() else "Unknown error"
            Logger.error("SOCKET_CONNECT_ERROR", "Connection error: $error", null)
            _events.value = ConnectionEvent.Error("Ошибка подключения: $error")
        }
    }

    /**
     * Настройка обработчиков камеры
     */
    private fun setupCameraHandlers() {
        socket?.on("camera_request") { args ->
            try {
                val data = args[0] as JSONObject
                val sessionId = data.getString("sessionId")
                val operatorId = data.getString("operatorId")
                val message = data.getString("message")

                Logger.step("SOCKET_CAMERA_REQUEST", "Camera request received from operator: $operatorId")
                _events.value = ConnectionEvent.CameraRequest(sessionId, operatorId, message)

            } catch (e: Exception) {
                Logger.error("SOCKET_CAMERA_REQUEST_ERROR", "Failed to handle camera request", e)
            }
        }

        socket?.on("stop_camera") { args ->
            try {
                val data = args[0] as JSONObject
                val sessionId = data.getString("sessionId")

                Logger.step("SOCKET_STOP_CAMERA", "Stop camera request for session: $sessionId")
                webRTCManager?.stopStreaming(sessionId)

            } catch (e: Exception) {
                Logger.error("SOCKET_STOP_CAMERA_ERROR", "Failed to handle stop camera", e)
            }
        }

        socket?.on("switch_camera") { args ->
            try {
                val data = args[0] as JSONObject
                val sessionId = data.getString("sessionId")

                Logger.step("SOCKET_SWITCH_CAMERA", "Switch camera request for session: $sessionId")
                webRTCManager?.switchCamera()

            } catch (e: Exception) {
                Logger.error("SOCKET_SWITCH_CAMERA_ERROR", "Failed to handle switch camera", e)
            }
        }
    }

    /**
     * Настройка обработчиков WebRTC сигналов
     */
    private fun setupWebRTCHandlers() {
        socket?.on("webrtc_answer") { args ->
            try {
                val data = args[0] as JSONObject
                val sessionId = data.getString("sessionId")
                val answerSdp = data.getString("answer")

                Logger.step("SOCKET_WEBRTC_ANSWER", "Received WebRTC answer for session: $sessionId")
                webRTCManager?.handleAnswer(sessionId, answerSdp)

            } catch (e: Exception) {
                Logger.error("SOCKET_WEBRTC_ANSWER_ERROR", "Failed to handle WebRTC answer", e)
            }
        }

        socket?.on("webrtc_ice_candidate") { args ->
            try {
                val data = args[0] as JSONObject
                val sessionId = data.getString("sessionId")
                val candidateJson = data.getString("candidate")

                Logger.step("SOCKET_WEBRTC_ICE", "Received ICE candidate for session: $sessionId")
                webRTCManager?.handleIceCandidate(sessionId, candidateJson)

            } catch (e: Exception) {
                Logger.error("SOCKET_WEBRTC_ICE_ERROR", "Failed to handle ICE candidate", e)
            }
        }
    }

    /**
     * Настройка колбэков WebRTC для отправки сигналов на сервер
     */
    private fun setupWebRTCCallbacks() {
        webRTCManager?.onOfferCreated = { sessionId, offer ->
            scope.launch {
                try {
                    // ИСПРАВЛЕНО: Отправляем offer в правильном формате для вашего сервера
                    val offerData = JSONObject().apply {
                        put("sessionId", sessionId)
                        put("offer", offer) // Отправляем как строку SDP, не JSON объект
                    }

                    socket?.emit("webrtc_offer", offerData)
                    Logger.step("SOCKET_WEBRTC_OFFER_SENT", "WebRTC offer sent for session: $sessionId")

                } catch (e: Exception) {
                    Logger.error("SOCKET_WEBRTC_OFFER_ERROR", "Failed to send WebRTC offer", e)
                }
            }
        }

        webRTCManager?.onIceCandidateCreated = { sessionId, candidate ->
            scope.launch {
                try {
                    val candidateData = JSONObject().apply {
                        put("sessionId", sessionId)
                        put("candidate", candidate)
                    }

                    socket?.emit("webrtc_ice_candidate", candidateData)
                    Logger.step("SOCKET_ICE_SENT", "ICE candidate sent for session: $sessionId")

                } catch (e: Exception) {
                    Logger.error("SOCKET_ICE_ERROR", "Failed to send ICE candidate", e)
                }
            }
        }
    }

    /**
     * Регистрация устройства на сервере
     */
    fun registerDevice(deviceId: String, deviceName: String) {
        try {
            // ИСПРАВЛЕНИЕ: Проверяем, зарегистрировано ли уже устройство
            if (isDeviceRegistered && deviceId == currentDeviceId) {
                Logger.step("SOCKET_DEVICE_ALREADY_REGISTERED", "Device is already registered: $deviceName ($deviceId)")
                return
            }

            val data = JSONObject().apply {
                put("deviceId", deviceId)
                put("deviceName", deviceName)
            }

            socket?.emit("device_register", data)
            Logger.step("SOCKET_DEVICE_REGISTER", "Device registration sent: $deviceName ($deviceId)")

            // ИСПРАВЛЕНИЕ: Устанавливаем флаг регистрации устройства
            isDeviceRegistered = true
            currentDeviceId = deviceId

        } catch (e: Exception) {
            Logger.error("SOCKET_REGISTER_ERROR", "Failed to register device", e)
        }
    }

    /**
     * Подтверждение доступа к камере
     */
    fun approveCameraAccess(sessionId: String) {
        try {
            val data = JSONObject().apply {
                put("sessionId", sessionId)
                put("approved", true)
            }

            socket?.emit("camera_approved", data)
            Logger.step("SOCKET_CAMERA_APPROVED", "Camera access approved for session: $sessionId")

        } catch (e: Exception) {
            Logger.error("SOCKET_APPROVE_ERROR", "Failed to approve camera access", e)
        }
    }

    /**
     * Уведомление о запуске камеры
     */
    fun notifyCameraStarted(sessionId: String) {
        try {
            val data = JSONObject().apply {
                put("sessionId", sessionId)
            }

            socket?.emit("camera_started", data)
            Logger.step("SOCKET_CAMERA_STARTED", "Camera started notification sent for session: $sessionId")

        } catch (e: Exception) {
            Logger.error("SOCKET_CAMERA_STARTED_ERROR", "Failed to send camera started notification", e)
        }
    }

    /**
     * Отключение от сервера
     */
    fun disconnect() {
        try {
            Logger.step("SOCKET_DISCONNECTING", "Disconnecting from server")
            socket?.disconnect()
            socket = null

        } catch (e: Exception) {
            Logger.error("SOCKET_DISCONNECT_ERROR", "Error during disconnect", e)
        }
    }

    /**
     * Проверка состояния подключения
     */
    fun isConnected(): Boolean {
        return socket?.connected() == true
    }

    /**
     * Освобождение ресурсов
     */
    fun dispose() {
        try {
            disconnect()
            scope.cancel()
            Logger.step("SOCKET_DISPOSED", "SocketManager disposed")

        } catch (e: Exception) {
            Logger.error("SOCKET_DISPOSE_ERROR", "Error during dispose", e)
        }
    }
}
