package com.example.elva.data.websocket

import com.example.elva.data.remote.model.emergency.AlertResponseWS
import com.example.elva.data.remote.model.emergency.AlertUpdateWS
import com.example.elva.data.remote.model.emergency.EmergencyAlertWS
import com.example.elva.data.remote.model.emergency.WebSocketMessage
import com.example.elva.util.AuthManager
import kotlinx.coroutines.*
import kotlinx.serialization.json.Json
import okhttp3.*
import java.util.concurrent.TimeUnit
import javax.inject.Inject
import javax.inject.Singleton

@Singleton
class EmergencyWebSocketManager @Inject constructor(
    private val authManager: AuthManager
) {

    private var webSocket: WebSocket? = null
    private var isConnected = false
    private var reconnectAttempts = 0
    private val maxReconnectAttempts = 5
    private val listeners = mutableListOf<WebSocketEventListener>()
    private val scope = CoroutineScope(Dispatchers.IO + SupervisorJob())

    // Замените на ваш IP адрес
    private companion object {
        private const val WS_HOST = "192.168.0.112"
        private const val WS_PORT = 8002
    }

    private val json = Json {
        ignoreUnknownKeys = true
        isLenient = true
    }

    private val client = OkHttpClient.Builder()
        .readTimeout(30, TimeUnit.SECONDS)
        .writeTimeout(30, TimeUnit.SECONDS)
        .pingInterval(25, TimeUnit.SECONDS)
        .build()

    // ==================== ПОДКЛЮЧЕНИЕ ====================

    fun connect() {
        val token = authManager.getAccessToken()
        val userId = authManager.getUserId()

        if (token == null || userId == -1) {
            notifyError("Authentication required")
            return
        }

        val wsUrl = "ws://$WS_HOST:$WS_PORT/api/v1/emergency/ws/$userId?token=$token"

        val request = Request.Builder()
            .url(wsUrl)
            .build()

        webSocket = client.newWebSocket(request, createWebSocketListener())
    }

    fun disconnect() {
        webSocket?.close(1000, "User disconnected")
        webSocket = null
        isConnected = false
        stopPingJob()
    }

    // ==================== СЛУШАТЕЛЬ WEBSOCKET ====================

    private fun createWebSocketListener(): WebSocketListener {
        return object : WebSocketListener() {

            override fun onOpen(webSocket: WebSocket, response: Response) {
                isConnected = true
                reconnectAttempts = 0
                startPingJob()
                notifyConnectionOpened()
            }

            override fun onMessage(webSocket: WebSocket, text: String) {
                handleIncomingMessage(text)
            }

            override fun onClosing(webSocket: WebSocket, code: Int, reason: String) {
                isConnected = false
                stopPingJob()
                notifyConnectionClosing(code, reason)
            }

            override fun onClosed(webSocket: WebSocket, code: Int, reason: String) {
                isConnected = false
                stopPingJob()
                notifyConnectionClosed(code, reason)
            }

            override fun onFailure(webSocket: WebSocket, t: Throwable, response: Response?) {
                isConnected = false
                stopPingJob()
                notifyError("Connection failed: ${t.message}")
                scheduleReconnect()
            }
        }
    }

    // ==================== ОБРАБОТКА СООБЩЕНИЙ ====================

    private fun handleIncomingMessage(text: String) {
        try {
            val message = json.decodeFromString<WebSocketMessage>(text)

            when (message.type) {
                "connection_established" -> {
                    notifyConnectionEstablished(message.userId ?: -1)
                }
                "emergency_alert" -> {
                    val alert = json.decodeFromString<EmergencyAlertWS>(text)
                    notifyNewEmergencyAlert(alert)
                }
                "alert_update" -> {
                    val update = json.decodeFromString<AlertUpdateWS>(text)
                    notifyAlertUpdate(update)
                }
                "alert_response" -> {
                    val response = json.decodeFromString<AlertResponseWS>(text)
                    notifyAlertResponse(response)
                }
                "pong" -> {
                    // Pong получен, соединение активно
                }
            }
        } catch (e: Exception) {
            notifyError("Failed to parse message: ${e.message}")
        }
    }

    // ==================== PING/PONG ====================

    private var pingJob: Job? = null

    private fun startPingJob() {
        pingJob = scope.launch {
            while (isConnected) {
                delay(30_000) // Ping каждые 30 секунд
                sendPing()
            }
        }
    }

    private fun stopPingJob() {
        pingJob?.cancel()
        pingJob = null
    }

    private fun sendPing() {
        if (isConnected) {
            webSocket?.send("""{"type": "ping"}""")
        }
    }

    // ==================== ПЕРЕПОДКЛЮЧЕНИЕ ====================

    private fun scheduleReconnect() {
        if (reconnectAttempts >= maxReconnectAttempts) {
            notifyError("Max reconnection attempts reached")
            return
        }

        reconnectAttempts++
        val delay = (reconnectAttempts * 2000).toLong() // Экспоненциальная задержка

        scope.launch {
            delay(delay)
            if (!isConnected) {
                connect()
            }
        }
    }

    // ==================== ОТПРАВКА СООБЩЕНИЙ ====================

    fun sendAlertReceived(alertId: Int) {
        val message = """{"type": "alert_received", "alert_id": $alertId}"""
        webSocket?.send(message)
    }

    // ==================== СЛУШАТЕЛИ ====================

    fun addListener(listener: WebSocketEventListener) {
        listeners.add(listener)
    }

    fun removeListener(listener: WebSocketEventListener) {
        listeners.remove(listener)
    }

    private fun notifyConnectionOpened() {
        listeners.forEach { it.onConnectionOpened() }
    }

    private fun notifyConnectionEstablished(userId: Int) {
        listeners.forEach { it.onConnectionEstablished(userId) }
    }

    private fun notifyNewEmergencyAlert(alert: EmergencyAlertWS) {
        listeners.forEach { it.onNewEmergencyAlert(alert) }
    }

    private fun notifyAlertUpdate(update: AlertUpdateWS) {
        listeners.forEach { it.onAlertUpdate(update) }
    }

    private fun notifyAlertResponse(response: AlertResponseWS) {
        listeners.forEach { it.onAlertResponse(response) }
    }

    private fun notifyConnectionClosing(code: Int, reason: String) {
        listeners.forEach { it.onConnectionClosing(code, reason) }
    }

    private fun notifyConnectionClosed(code: Int, reason: String) {
        listeners.forEach { it.onConnectionClosed(code, reason) }
    }

    private fun notifyError(error: String) {
        listeners.forEach { it.onError(error) }
    }

    // ==================== СОСТОЯНИЕ ====================

    fun isConnected(): Boolean = isConnected

    fun cleanup() {
        disconnect()
        scope.cancel()
    }
}

