package ru.forbion.f7cloud.feature.talk

import android.content.Context
import org.json.JSONObject
import ru.forbion.f7cloud.core.auth.AuthSession

class TalkOfflineRepository(context: Context) {
    private val dao = TalkOfflineDatabase.get(context).dao()

    suspend fun cacheRooms(rooms: List<TalkRoom>) {
        val now = System.currentTimeMillis()
        dao.upsertRooms(
            rooms.map { room ->
                TalkRoomEntity(
                    token = room.token,
                    displayName = room.displayName,
                    type = room.type,
                    unreadMessages = room.unreadMessages,
                    hasCall = room.hasCall,
                    isFavorite = room.isFavorite,
                    lastActivity = room.lastActivity,
                    lastMessagePreview = room.lastMessagePreview,
                    syncedAt = now,
                )
            },
        )
    }

    suspend fun cachedRooms(): List<TalkRoom> =
        dao.allRooms().map { entity ->
            TalkRoom(
                token = entity.token,
                displayName = entity.displayName,
                type = entity.type,
                unreadMessages = entity.unreadMessages,
                hasCall = entity.hasCall,
                isFavorite = entity.isFavorite,
                lastActivity = entity.lastActivity,
                lastMessagePreview = entity.lastMessagePreview,
            )
        }

    suspend fun cacheMessages(roomToken: String, messages: List<TalkMessage>) {
        dao.upsertMessages(
            messages.map { msg ->
                TalkMessageEntity(
                    id = msg.id,
                    roomToken = roomToken,
                    actorDisplayName = msg.actorDisplayName,
                    actorId = msg.actorId,
                    text = msg.text,
                    timestamp = msg.timestamp,
                    messageType = msg.messageType,
                    replyToId = msg.replyToId,
                    reactionsJson = reactionsToJson(msg.reactions),
                    messageParametersJson = messageParametersToJson(msg.messageParameters),
                )
            },
        )
    }

    suspend fun cachedMessages(roomToken: String): List<TalkMessage> =
        dao.messagesForRoom(roomToken).map { entity ->
            TalkMessage(
                id = entity.id,
                actorDisplayName = entity.actorDisplayName,
                actorId = entity.actorId,
                text = entity.text,
                timestamp = entity.timestamp,
                messageType = entity.messageType,
                replyToId = entity.replyToId,
                reactions = jsonToReactions(entity.reactionsJson),
                messageParameters = jsonToMessageParameters(entity.messageParametersJson),
            )
        }

    private fun reactionsToJson(reactions: Map<String, Int>): String? {
        if (reactions.isEmpty()) return null
        val o = JSONObject()
        reactions.forEach { (emoji, count) -> o.put(emoji, count) }
        return o.toString()
    }

    private fun jsonToReactions(json: String?): Map<String, Int> {
        if (json.isNullOrBlank()) return emptyMap()
        return runCatching {
            val o = JSONObject(json)
            buildMap {
                o.keys().forEach { key ->
                    put(key, o.optInt(key, 0))
                }
            }
        }.getOrDefault(emptyMap())
    }

    private fun messageParametersToJson(parameters: Map<String, TalkMessageParameter>): String? {
        if (parameters.isEmpty()) return null
        val root = JSONObject()
        parameters.forEach { (key, param) ->
            root.put(
                key,
                JSONObject().apply {
                    put("type", param.type)
                    put("name", param.name)
                    if (param.id.isNotBlank()) put("id", param.id)
                },
            )
        }
        return root.toString()
    }

    private fun jsonToMessageParameters(json: String?): Map<String, TalkMessageParameter> {
        if (json.isNullOrBlank()) return emptyMap()
        return runCatching {
            val root = JSONObject(json)
            buildMap {
                root.keys().forEach { key ->
                    val obj = root.optJSONObject(key) ?: return@forEach
                    put(
                        key,
                        TalkMessageParameter(
                            type = obj.optString("type"),
                            name = obj.optString("name"),
                            id = obj.optString("id"),
                        ),
                    )
                }
            }
        }.getOrDefault(emptyMap())
    }
}
