package de.tsschulz.tt_tagebuch.shared.api

import io.socket.client.IO
import io.socket.client.Socket
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.asSharedFlow
import org.json.JSONObject

class SocketService(private val socketUrl: String) {
    private var socket: Socket? = null
    private var currentClubId: Int? = null
    
    private val _events = MutableSharedFlow<Pair<String, JSONObject>>(extraBufferCapacity = 64)
    val events = _events.asSharedFlow()

    fun connect(clubId: Int) {
        val existing = socket
        if (existing != null) {
            val previousClubId = currentClubId
            if (previousClubId != null && previousClubId != clubId) {
                existing.emit("leave-club", previousClubId)
            }
            currentClubId = clubId
            if (existing.connected()) {
                existing.emit("join-club", clubId)
            }
            return
        }

        val options = IO.Options().apply {
            path = "/socket.io/"
            transports = arrayOf("polling", "websocket")
            reconnection = true
            reconnectionAttempts = Int.MAX_VALUE
            reconnectionDelay = 1_000
            reconnectionDelayMax = 5_000
            timeout = 20_000
            forceNew = false
        }
        
        currentClubId = clubId
        socket = IO.socket(normalizedSocketUrl(), options)
        
        socket?.on(Socket.EVENT_CONNECT) {
            println("✅ Connected to Socket.IO")
            currentClubId?.let { socket?.emit("join-club", it) }
        }

        socket?.on(Socket.EVENT_DISCONNECT) {
            println("❌ Socket.IO disconnected")
        }
        
        realtimeEvents.forEach { eventName ->
            socket?.on(eventName) { args ->
                val data = args.firstOrNull() as? JSONObject ?: JSONObject()
                _events.tryEmit(eventName to data)
            }
        }

        socket?.connect()
    }

    fun disconnect() {
        currentClubId?.let { socket?.emit("leave-club", it) }
        socket?.disconnect()
        socket?.off()
        socket = null
        currentClubId = null
    }

    private fun normalizedSocketUrl(): String =
        socketUrl
            .replaceFirst("wss://", "https://")
            .replaceFirst("ws://", "http://")

    private companion object {
        val realtimeEvents = listOf(
            "participant:added",
            "participant:removed",
            "participant:updated",
            "diary:note:added",
            "diary:note:updated",
            "diary:note:deleted",
            "diary:tag:added",
            "diary:tag:removed",
            "diary:date:updated",
            "activity:member:added",
            "activity:member:removed",
            "activity:changed",
            "member:changed",
            "group:changed",
            "tournament:changed",
            "schedule:match:updated",
            "schedule:match-report:submitted",
            "friendly:invitation:created",
            "friendly:invitation:accepted",
            "friendly:invitation:declined",
            "friendly:shared:match:updated",
            "friendly:shared:match:deleted",
        )
    }
}
