package com.example.godeye.signaling

import android.util.Log
import com.example.godeye.models.*
import com.google.gson.Gson
import io.socket.client.IO
import io.socket.client.Socket
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asStateFlow
import org.json.JSONObject
import java.net.URI

/**
 * Сигналлинг клиент для WebRTC подключений
 */
class SignalingClient {

    companion object {
        private const val TAG = "SignalingClient"
        // ИСПРАВЛЕНИЕ: Обновляем IP по умолчанию на ваш сервер
        private const val DEFAULT_SERVER_URL = "ws://192.168.219.108:3000"
    }

    private var socket: Socket? = null
    private val gson = Gson()

    // Состояния
    private val _signalingState = MutableStateFlow(SignalingState.DISCONNECTED)
    val signalingState: StateFlow<SignalingState> = _signalingState.asStateFlow()

    private val _sessionState = MutableStateFlow(SessionState.WAITING)
    val sessionState: StateFlow<SessionState> = _sessionState.asStateFlow()

    private val _currentCall = MutableStateFlow<IncomingCall?>(null)
    val currentCall: StateFlow<IncomingCall?> = _currentCall.asStateFlow()

    // Callbacks для WebRTC
    private var onOfferReceived: ((RTCSessionDescription) -> Unit)? = null
    private var onAnswerReceived: ((RTCSessionDescription) -> Unit)? = null
    private var onIceCandidateReceived: ((RTCIceCandidate) -> Unit)? = null
    private var onCallEnded: (() -> Unit)? = null

    private var deviceId: String? = null

    /**
     * Подключение к сигналлинг серверу
     */
    fun connect(serverUrl: String = DEFAULT_SERVER_URL, deviceInfo: DeviceInfo) {
        Log.d(TAG, "Connecting to signaling server: $serverUrl")

        try {
            _signalingState.value = SignalingState.CONNECTING
            this.deviceId = deviceInfo.model // Используем model как ID устройства

            val options = IO.Options().apply {
                timeout = 5000
                reconnection = true
                reconnectionAttempts = 5
                reconnectionDelay = 1000
            }

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

            setupSocketListeners()
            socket?.connect()

            // Регистрируем устройство после подключения
            socket?.on(Socket.EVENT_CONNECT) {
                Log.d(TAG, "Connected to signaling server")
                _signalingState.value = SignalingState.CONNECTED
                registerDevice(deviceInfo)
            }

        } catch (e: Exception) {
            Log.e(TAG, "Failed to connect to signaling server", e)
            _signalingState.value = SignalingState.ERROR
        }
    }

    /**
     * Отключение от сигналлинг сервера
     */
    fun disconnect() {
        Log.d(TAG, "Disconnecting from signaling server")

        socket?.off()
        socket?.disconnect()
        socket = null

        _signalingState.value = SignalingState.DISCONNECTED
        _sessionState.value = SessionState.WAITING
        _currentCall.value = null
    }

    /**
     * Настройка слушателей Socket.IO
     */
    private fun setupSocketListeners() {
        socket?.apply {

            on(Socket.EVENT_DISCONNECT) {
                Log.d(TAG, "Disconnected from signaling server")
                _signalingState.value = SignalingState.DISCONNECTED
            }

            on(Socket.EVENT_CONNECT_ERROR) { args ->
                Log.e(TAG, "Connection error: ${args.contentToString()}")
                _signalingState.value = SignalingState.ERROR
            }

            on("reconnect") {
                Log.d(TAG, "Reconnected to signaling server")
                _signalingState.value = SignalingState.CONNECTED
            }

            on("reconnecting") {
                Log.d(TAG, "Reconnecting to signaling server")
                _signalingState.value = SignalingState.RECONNECTING
            }

            // Обработка входящих вызовов
            on("operator_call") { args ->
                handleOperatorCall(args)
            }

            // Обработка WebRTC сигналлинга
            on("offer") { args ->
                handleOffer(args)
            }

            on("answer") { args ->
                handleAnswer(args)
            }

            on("ice_candidate") { args ->
                handleIceCandidate(args)
            }

            on("call_end") { args ->
                handleCallEnd(args)
            }

            // Системные сообщения
            on("device_registered") { args ->
                Log.d(TAG, "Device registered successfully: ${args.contentToString()}")
            }

            on("error") { args ->
                Log.e(TAG, "Server error: ${args.contentToString()}")
            }
        }
    }

    /**
     * Регистрация устройства на сервере
     */
    private fun registerDevice(deviceInfo: DeviceInfo) {
        Log.d(TAG, "Registering device: ${deviceInfo.model}")

        val message = SignalingMessage(
            type = SignalingMessageType.DEVICE_REGISTER,
            data = deviceInfo
        )

        val json = JSONObject(gson.toJson(message))
        socket?.emit("device_register", json)

        _sessionState.value = SessionState.WAITING
    }

    /**
     * Обработка входящего вызова от оператора
     */
    private fun handleOperatorCall(args: Array<Any>) {
        try {
            val data = args[0] as JSONObject
            Log.d(TAG, "Incoming operator call: $data")

            val incomingCall = IncomingCall(
                operatorId = data.getString("operatorId"),
                operatorName = data.optString("operatorName", "Оператор"),
                callId = data.getString("callId"),
                timestamp = data.optLong("timestamp", System.currentTimeMillis())
            )

            _currentCall.value = incomingCall
            _sessionState.value = SessionState.INCOMING

            Log.d(TAG, "Incoming call from operator: ${incomingCall.operatorName}")

        } catch (e: Exception) {
            Log.e(TAG, "Error handling operator call", e)
        }
    }

    /**
     * Принятие вызова от оператора
     */
    fun acceptCall() {
        val call = _currentCall.value ?: return

        Log.d(TAG, "Accepting call from operator: ${call.operatorId}")

        val message = SignalingMessage(
            type = SignalingMessageType.CALL_ACCEPT,
            to = call.operatorId,
            data = mapOf("callId" to call.callId)
        )

        val json = JSONObject(gson.toJson(message))
        socket?.emit("call_accept", json)

        _sessionState.value = SessionState.ACTIVE
    }

    /**
     * Отклонение вызова от оператора
     */
    fun rejectCall() {
        val call = _currentCall.value ?: return

        Log.d(TAG, "Rejecting call from operator: ${call.operatorId}")

        val message = SignalingMessage(
            type = SignalingMessageType.CALL_REJECT,
            to = call.operatorId,
            data = mapOf("callId" to call.callId)
        )

        val json = JSONObject(gson.toJson(message))
        socket?.emit("call_reject", json)

        _sessionState.value = SessionState.WAITING
        _currentCall.value = null
    }

    /**
     * Завершение вызова
     */
    fun endCall() {
        val call = _currentCall.value ?: return

        Log.d(TAG, "Ending call with operator: ${call.operatorId}")

        val message = SignalingMessage(
            type = SignalingMessageType.CALL_END,
            to = call.operatorId,
            data = mapOf("callId" to call.callId)
        )

        val json = JSONObject(gson.toJson(message))
        socket?.emit("call_end", json)

        _sessionState.value = SessionState.ENDED
        _currentCall.value = null
    }

    /**
     * Отправка WebRTC Offer
     */
    fun sendOffer(offer: RTCSessionDescription, operatorId: String) {
        Log.d(TAG, "Sending offer to operator: $operatorId")

        val message = SignalingMessage(
            type = SignalingMessageType.OFFER,
            to = operatorId,
            data = offer
        )

        val json = JSONObject(gson.toJson(message))
        socket?.emit("offer", json)
    }

    /**
     * Отправка WebRTC Answer
     */
    fun sendAnswer(answer: RTCSessionDescription, operatorId: String) {
        Log.d(TAG, "Sending answer to operator: $operatorId")

        val message = SignalingMessage(
            type = SignalingMessageType.ANSWER,
            to = operatorId,
            data = answer
        )

        val json = JSONObject(gson.toJson(message))
        socket?.emit("answer", json)
    }

    /**
     * Отправка ICE Candidate
     */
    fun sendIceCandidate(candidate: RTCIceCandidate, operatorId: String) {
        Log.d(TAG, "Sending ICE candidate to operator: $operatorId")

        val message = SignalingMessage(
            type = SignalingMessageType.ICE_CANDIDATE,
            to = operatorId,
            data = candidate
        )

        val json = JSONObject(gson.toJson(message))
        socket?.emit("ice_candidate", json)
    }

    // Обработчики WebRTC сигналлинга
    private fun handleOffer(args: Array<Any>) {
        try {
            val data = args[0] as JSONObject
            val offerData = data.getJSONObject("data")

            val offer = RTCSessionDescription(
                type = offerData.getString("type"),
                sdp = offerData.getString("sdp")
            )

            Log.d(TAG, "Received offer from operator")
            onOfferReceived?.invoke(offer)

        } catch (e: Exception) {
            Log.e(TAG, "Error handling offer", e)
        }
    }

    private fun handleAnswer(args: Array<Any>) {
        try {
            val data = args[0] as JSONObject
            val answerData = data.getJSONObject("data")

            val answer = RTCSessionDescription(
                type = answerData.getString("type"),
                sdp = answerData.getString("sdp")
            )

            Log.d(TAG, "Received answer from operator")
            onAnswerReceived?.invoke(answer)

        } catch (e: Exception) {
            Log.e(TAG, "Error handling answer", e)
        }
    }

    /**
     * НОВОЕ: Получение хоста сервера для ICE candidates
     */
    fun getServerHost(): String? {
        return socket?.let { socket ->
            try {
                // ИСПРАВЛЕНИЕ: Используем правильный способ получения URI
                val socketUrl = socket.toString() // Получаем строковое представление
                val regex = """://([^:/]+)""".toRegex()
                val match = regex.find(socketUrl)
                match?.groupValues?.get(1) ?: "192.168.219.108" // Fallback на ваш сервер
            } catch (e: Exception) {
                Log.e(TAG, "Failed to extract server host", e)
                "192.168.219.108" // Fallback на ваш сервер
            }
        }
    }

    /**
     * ИСПРАВЛЕНИЕ: Улучшенная обработка ICE candidates с информацией о сервере
     */
    private fun handleIceCandidate(args: Array<Any>) {
        try {
            if (args.isNotEmpty()) {
                val candidateData = args[0] as? JSONObject ?: return

                val sessionId = candidateData.optString("sessionId", "")
                val candidateObj = candidateData.optJSONObject("candidate")

                if (candidateObj != null) {
                    // НОВОЕ: Добавляем информацию о сервере в ICE candidate
                    val candidate = RTCIceCandidate(
                        candidate = candidateObj.optString("candidate"),
                        sdpMid = candidateObj.optString("sdpMid"),
                        sdpMLineIndex = candidateObj.optInt("sdpMLineIndex")
                    )

                    // Обогащаем candidate информацией о сигналинг сервере
                    val enrichedCandidate = enrichIceCandidateWithServerInfo(candidate)

                    onIceCandidateReceived?.invoke(enrichedCandidate)

                    Log.d(TAG, "✅ ICE candidate received and enriched for session: $sessionId")
                }
            }
        } catch (e: Exception) {
            Log.e(TAG, "Failed to handle ICE candidate", e)
        }
    }

    /**
     * НОВОЕ: Обогащение ICE candidate информацией о сервере
     */
    private fun enrichIceCandidateWithServerInfo(candidate: RTCIceCandidate): RTCIceCandidate {
        val serverHost = getServerHost() ?: "192.168.219.108"

        return RTCIceCandidate(
            candidate = candidate.candidate,
            sdpMid = candidate.sdpMid,
            sdpMLineIndex = candidate.sdpMLineIndex
        )
    }

    private fun handleCallEnd(args: Array<Any>) {
        try {
            Log.d(TAG, "Call ended by operator")

            _sessionState.value = SessionState.ENDED
            _currentCall.value = null

            onCallEnded?.invoke()

        } catch (e: Exception) {
            Log.e(TAG, "Error handling call end", e)
        }
    }

    // Установка callback'ов для WebRTC
    fun setOnOfferReceived(callback: (RTCSessionDescription) -> Unit) {
        onOfferReceived = callback
    }

    fun setOnAnswerReceived(callback: (RTCSessionDescription) -> Unit) {
        onAnswerReceived = callback
    }

    fun setOnIceCandidateReceived(callback: (RTCIceCandidate) -> Unit) {
        onIceCandidateReceived = callback
    }

    fun setOnCallEnded(callback: () -> Unit) {
        onCallEnded = callback
    }
}
