package com.example.godeye.services

import android.app.Notification
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.Service
import android.content.Intent
import android.os.Binder
import android.os.Build
import android.os.IBinder
import androidx.core.app.NotificationCompat
import com.example.godeye.R
import com.example.godeye.models.*
import com.example.godeye.utils.Logger
import com.google.gson.Gson
import com.google.gson.JsonObject
import io.socket.client.IO
import io.socket.client.Socket
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.SupervisorJob
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.launch
import org.json.JSONArray
import org.json.JSONObject
import java.net.URI

/**
 * SocketService - основной сервис для WebSocket соединения с backend сервером
 * Работает в фоне и обеспечивает постоянное соединение с сервером
 */
class SocketService : Service() {

    private val binder = LocalBinder()
    private var socket: Socket? = null
    private val gson = Gson()
    private val serviceScope = CoroutineScope(SupervisorJob() + Dispatchers.IO)

    // Состояния сервиса
    private val _connectionState = MutableStateFlow(ConnectionState.DISCONNECTED)
    val connectionState: StateFlow<ConnectionState> = _connectionState.asStateFlow()

    private val _deviceId = MutableStateFlow("")
    val deviceId: StateFlow<String> = _deviceId.asStateFlow()

    // События для передачи в UI
    private val _cameraRequests = MutableStateFlow<CameraRequest?>(null)
    val cameraRequests: StateFlow<CameraRequest?> = _cameraRequests.asStateFlow()

    private val _webRTCEvents = MutableStateFlow<WebRTCEvent?>(null)
    val webRTCEvents: StateFlow<WebRTCEvent?> = _webRTCEvents.asStateFlow()

    inner class LocalBinder : Binder() {
        fun getService(): SocketService = this@SocketService
    }

    override fun onBind(intent: Intent): IBinder = binder

    override fun onCreate() {
        super.onCreate()
        Logger.step("SOCKET_SERVICE_CREATE", "SocketService created")
        createNotificationChannel()
        startForeground(NOTIFICATION_ID, createNotification())
    }

    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        Logger.step("SOCKET_SERVICE_START", "SocketService started")
        return START_STICKY // Перезапускать сервис при убийстве системой
    }

    /**
     * Подключение к backend серверу по Socket.IO
     */
    fun connect(serverUrl: String, deviceId: String) {
        Logger.step("SOCKET_CONNECT", "Connecting to server: $serverUrl")
        _deviceId.value = deviceId
        _connectionState.value = ConnectionState.CONNECTING

        serviceScope.launch {
            try {
                val uri = URI.create(serverUrl)
                val options = IO.Options().apply {
                    timeout = 10000
                    reconnection = true
                    reconnectionAttempts = 5
                    reconnectionDelay = 1000
                }

                socket = IO.socket(uri, options)
                setupEventListeners()
                socket?.connect()

            } catch (e: Exception) {
                Logger.error("SOCKET_CONNECT_ERROR", "Failed to connect to server", e)
                _connectionState.value = ConnectionState.ERROR
            }
        }
    }

    /**
     * Настройка обработчиков событий Socket.IO
     */
    private fun setupEventListeners() {
        socket?.apply {
            // Событие подключения
            on(Socket.EVENT_CONNECT) {
                Logger.step("SOCKET_CONNECTED", "Connected to server")
                _connectionState.value = ConnectionState.CONNECTED
                registerDevice()
            }

            // Событие отключения
            on(Socket.EVENT_DISCONNECT) {
                Logger.step("SOCKET_DISCONNECTED", "Disconnected from server")
                _connectionState.value = ConnectionState.DISCONNECTED
            }

            // Событие подключения (исправлено)
            on(Socket.EVENT_CONNECT) {
                Logger.step("SOCKET_RECONNECTED", "Reconnected to server")
                _connectionState.value = ConnectionState.CONNECTED
                registerDevice()
            }

            // Успешная регистрация устройства
            on("register:success") { args ->
                Logger.step("REGISTER_SUCCESS", "Device registered successfully")
                val response = args[0] as JSONObject
                Logger.d("Registration response: $response")
            }

            // Запрос доступа к камере от оператора
            on("camera:request") { args ->
                try {
                    val requestData = args[0] as JSONObject
                    val cameraRequest = CameraRequest(
                        sessionId = requestData.getString("sessionId"),
                        operatorId = requestData.getString("operatorId"),
                        cameraType = requestData.getString("cameraType")
                    )

                    Logger.step("CAMERA_REQUEST_RECEIVED",
                        "Camera request from operator ${cameraRequest.operatorId} for ${cameraRequest.cameraType}")

                    _cameraRequests.value = cameraRequest

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

            // Завершение сессии
            on("camera:disconnect") { args ->
                try {
                    val data = args[0] as JSONObject
                    val sessionId = data.getString("sessionId")
                    Logger.step("CAMERA_DISCONNECT", "Session $sessionId ended by operator")

                    // Очистить текущий запрос если он совпадает
                    if (_cameraRequests.value?.sessionId == sessionId) {
                        _cameraRequests.value = null
                    }

                } catch (e: Exception) {
                    Logger.error("CAMERA_DISCONNECT_PARSE_ERROR", "Failed to parse disconnect event", e)
                }
            }

            // WebRTC offer от оператора
            on("webrtc:offer") { args ->
                try {
                    val data = args[0] as JSONObject
                    val event = WebRTCEvent.Offer(
                        sessionId = data.getString("sessionId"),
                        offer = data.getString("offer")
                    )

                    Logger.step("WEBRTC_OFFER_RECEIVED", "WebRTC offer received for session ${event.sessionId}")
                    _webRTCEvents.value = event

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

            // WebRTC answer от оператора
            on("webrtc:answer") { args ->
                try {
                    val data = args[0] as JSONObject
                    val event = WebRTCEvent.Answer(
                        sessionId = data.getString("sessionId"),
                        answer = data.getString("answer")
                    )

                    Logger.step("WEBRTC_ANSWER_RECEIVED", "WebRTC answer received for session ${event.sessionId}")
                    _webRTCEvents.value = event

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

            // ICE кандидаты
            on("webrtc:ice-candidate") { args ->
                try {
                    val data = args[0] as JSONObject
                    val event = WebRTCEvent.IceCandidate(
                        sessionId = data.getString("sessionId"),
                        candidate = data.getString("candidate"),
                        sdpMid = data.getString("sdpMid"),
                        sdpMLineIndex = data.getInt("sdpMLineIndex")
                    )

                    Logger.step("WEBRTC_ICE_RECEIVED", "ICE candidate received for session ${event.sessionId}")
                    _webRTCEvents.value = event

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

            // Переключение камеры
            on("camera:switch") { args ->
                try {
                    val data = args[0] as JSONObject
                    val sessionId = data.getString("sessionId")
                    val cameraType = data.getString("cameraType")

                    Logger.step("CAMERA_SWITCH_REQUEST", "Camera switch request: $cameraType for session $sessionId")

                    // Отправить событие переключения камеры
                    val event = WebRTCEvent.SwitchCamera(sessionId, cameraType)
                    _webRTCEvents.value = event

                } catch (e: Exception) {
                    Logger.error("CAMERA_SWITCH_PARSE_ERROR", "Failed to parse camera switch request", e)
                }
            }

            // Ошибки соединения
            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)
                _connectionState.value = ConnectionState.ERROR
            }
        }
    }

    /**
     * Регистрация Android устройства на сервере
     */
    private fun registerDevice() {
        val deviceInfo = DeviceInfo(
            deviceId = _deviceId.value,
            deviceName = "${android.os.Build.MANUFACTURER} ${android.os.Build.MODEL}",
            androidVersion = android.os.Build.VERSION.RELEASE,
            appVersion = "1.0.0"
        )

        val registerData = JSONObject().apply {
            put("deviceId", _deviceId.value)
            put("deviceInfo", JSONObject().apply {
                put("model", deviceInfo.deviceName)
                put("manufacturer", deviceInfo.manufacturer)
                put("androidVersion", deviceInfo.androidVersion)
                put("appVersion", deviceInfo.appVersion)
                put("availableCameras", JSONArray().apply {
                    deviceInfo.availableCameras.forEach { put(it) }
                })
            })
        }

        socket?.emit("register:android", registerData)
        Logger.step("REGISTER_DEVICE", "Device registration sent: ${deviceInfo.deviceName}")
    }

    /**
     * Отправка ответа на запрос камеры
     */
    fun sendCameraResponse(sessionId: String, accepted: Boolean, reason: String = "") {
        val responseData = JSONObject().apply {
            put("sessionId", sessionId)
            put("accepted", accepted)
            if (!accepted && reason.isNotEmpty()) {
                put("reason", reason)
            }
        }

        socket?.emit("camera:response", responseData)
        Logger.step("CAMERA_RESPONSE_SENT", "Camera response sent: sessionId=$sessionId, accepted=$accepted")
    }

    /**
     * Отправка WebRTC offer
     */
    fun sendWebRTCOffer(sessionId: String, offer: String) {
        val offerData = JSONObject().apply {
            put("sessionId", sessionId)
            put("offer", offer)
        }

        socket?.emit("webrtc:offer", offerData)
        Logger.step("WEBRTC_OFFER_SENT", "WebRTC offer sent for session $sessionId")
    }

    /**
     * Отправка WebRTC answer
     */
    fun sendWebRTCAnswer(sessionId: String, answer: String) {
        val answerData = JSONObject().apply {
            put("sessionId", sessionId)
            put("answer", answer)
        }

        socket?.emit("webrtc:answer", answerData)
        Logger.step("WEBRTC_ANSWER_SENT", "WebRTC answer sent for session $sessionId")
    }

    /**
     * Отправка ICE кандидата
     */
    fun sendIceCandidate(sessionId: String, candidate: String, sdpMid: String, sdpMLineIndex: Int) {
        val candidateData = JSONObject().apply {
            put("sessionId", sessionId)
            put("candidate", candidate)
            put("sdpMid", sdpMid)
            put("sdpMLineIndex", sdpMLineIndex)
        }

        socket?.emit("webrtc:ice-candidate", candidateData)
        Logger.step("WEBRTC_ICE_SENT", "ICE candidate sent for session $sessionId")
    }

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

    private fun createNotificationChannel() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channel = NotificationChannel(
                CHANNEL_ID,
                "GodEye Service",
                NotificationManager.IMPORTANCE_LOW
            ).apply {
                description = "Сервис подключения к серверу"
                setShowBadge(false)
            }

            val manager = getSystemService(NotificationManager::class.java)
            manager.createNotificationChannel(channel)
        }
    }

    private fun createNotification(): Notification {
        return NotificationCompat.Builder(this, CHANNEL_ID)
            .setContentTitle("GodEye")
            .setContentText("Подключено к серверу")
            .setSmallIcon(R.drawable.ic_launcher_foreground)
            .setOngoing(true)
            .setCategory(NotificationCompat.CATEGORY_SERVICE)
            .build()
    }

    override fun onDestroy() {
        Logger.step("SOCKET_SERVICE_DESTROY", "SocketService destroyed")
        disconnect()
        super.onDestroy()
    }

    companion object {
        private const val CHANNEL_ID = "godeye_service_channel"
        private const val NOTIFICATION_ID = 1001
    }
}

/**
 * События WebRTC для обработки в UI
 */
sealed class WebRTCEvent {
    object Connected : WebRTCEvent()
    object Disconnected : WebRTCEvent()
    data class Error(val message: String) : WebRTCEvent()
    data class Offer(val sessionId: String, val offer: String) : WebRTCEvent()
    data class Answer(val sessionId: String, val answer: String) : WebRTCEvent()
    data class IceCandidate(
        val sessionId: String,
        val candidate: String,
        val sdpMid: String,
        val sdpMLineIndex: Int
    ) : WebRTCEvent()
    data class SwitchCamera(val sessionId: String, val cameraType: String) : WebRTCEvent()
}
