package chat.rocket.android.chatrooms.adapter

import android.app.Application
import android.text.SpannableStringBuilder
import androidx.core.content.ContextCompat
import androidx.core.text.bold
import androidx.core.text.color
import chat.rocket.android.R
import chat.rocket.android.chatrooms.adapter.model.RoomUiModel
import chat.rocket.android.db.model.ChatRoom
import chat.rocket.android.infrastructure.LocalRepository
import chat.rocket.android.infrastructure.checkIfMyself
import chat.rocket.android.server.domain.PublicSettings
import chat.rocket.android.server.domain.showLastMessage
import chat.rocket.android.server.domain.useRealName
import chat.rocket.android.server.domain.useSpecialCharsOnRoom
import chat.rocket.android.util.extensions.avatarUrl
import chat.rocket.android.util.extensions.date
import chat.rocket.android.util.extensions.localDateTime
import chat.rocket.common.model.RoomType
import chat.rocket.common.model.roomTypeOf
import chat.rocket.common.model.userStatusOf

class RoomUiModelMapper(
    private val context: Application,
    private val settings: PublicSettings,
    private val localRepository: LocalRepository,
    private val serverUrl: String
) {
    private val nameUnreadColor = ContextCompat.getColor(context, R.color.colorPrimaryText)
    private val nameColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
    private val dateUnreadColor = ContextCompat.getColor(context, R.color.colorAccent)
    private val dateColor = ContextCompat.getColor(context, R.color.colorSecondaryText)
    private val messageUnreadColor = ContextCompat.getColor(context, android.R.color.primary_text_light)
    private val messageColor = ContextCompat.getColor(context, R.color.colorSecondaryText)

    fun map(rooms: List<ChatRoom>, grouped: Boolean): List<ItemHolder<*>> {
        val list = ArrayList<ItemHolder<*>>(rooms.size + 4)
        var lastType: String? = null
        rooms.forEach { room ->
            if (grouped && lastType != room.chatRoom.type) {
                list.add(HeaderItemHolder(roomType(room.chatRoom.type)))
            }
            list.add(RoomItemHolder(map(room)))
            lastType = room.chatRoom.type
        }

        return list
    }

    fun map(chatRoom: ChatRoom): RoomUiModel {
        return with(chatRoom.chatRoom) {
            val isUnread = alert || unread > 0
            val type = roomTypeOf(type)
            val status = chatRoom.status?.let { userStatusOf(it) }
            val roomName = mapName(name, chatRoom.userFullname, isUnread)
            val timestamp = mapDate(lastMessageTimestamp ?: updatedAt, isUnread)
            val avatar = if (type is RoomType.DirectMessage) {
                serverUrl.avatarUrl(name)
            } else {
                serverUrl.avatarUrl(name, isGroupOrChannel = true)
            }
            val unread = mapUnread(unread)
            val lastMessage = mapLastMessage(chatRoom.lastMessageUserName,
                    chatRoom.lastMessageUserFullName, lastMessageText, isUnread)

            RoomUiModel(
                id = id,
                name = roomName,
                type = type,
                avatar = avatar,
                date = timestamp,
                unread = unread,
                alert = isUnread,
                lastMessage = lastMessage,
                status = status
            )
        }
    }

    private fun roomType(type: String): String {
        val resources = context.resources
        return when (type) {
            RoomType.CHANNEL -> resources.getString(R.string.header_channel)
            RoomType.PRIVATE_GROUP -> resources.getString(R.string.header_private_groups)
            RoomType.DIRECT_MESSAGE -> resources.getString(R.string.header_direct_messages)
            RoomType.LIVECHAT -> resources.getString(R.string.header_live_chats)
            else -> resources.getString(R.string.header_unknown)
        }
    }

    private fun mapLastMessage(name: String?, fullName: String?, text: String?, unread: Boolean): CharSequence? {
        return if (!settings.showLastMessage()) {
            null
        } else if (name != null && text != null) {
            val user = if (localRepository.checkIfMyself(name)) {
                "${context.getString(R.string.msg_you)}: "
            } else {
                "${mapName(name, fullName, unread)}: "
            }

            val color = if (unread) messageUnreadColor else messageColor

            SpannableStringBuilder()
                    .color(color) {
                        bold { append(user) }
                        append(text)
                    }
        } else {
            context.getText(R.string.msg_no_messages_yet)
        }
    }

    private fun mapName(name: String, fullName: String?, unread: Boolean): CharSequence {
        val roomName = if (settings.useSpecialCharsOnRoom() || settings.useRealName()) {
            fullName ?: name
        } else {
            name
        }

        val color = if (unread) nameUnreadColor else nameColor
        return SpannableStringBuilder()
                .color(color) {
                    append(roomName)
                }
    }

    private fun mapUnread(unread: Long): String? {
        return when(unread) {
            0L -> null
            in 1..99 -> unread.toString()
            else -> context.getString(R.string.msg_more_than_ninety_nine_unread_messages)

        }
    }

    private fun mapDate(date: Long?, unread: Boolean): CharSequence? {
        return date?.localDateTime()?.date(context)?.let {
            val color = if (unread) dateUnreadColor else dateColor
            SpannableStringBuilder().color(color) {
                append(it)
            }
        }
    }
}