package org.thoughtcrime.securesms.home.search

import android.graphics.Typeface
import android.text.Spannable
import android.text.SpannableStringBuilder
import android.text.style.StyleSpan
import androidx.core.view.isVisible
import androidx.recyclerview.widget.DiffUtil
import network.loki.messenger.R
import org.session.libsession.messaging.contacts.Contact
import org.session.libsession.utilities.Address
import org.session.libsession.utilities.recipients.Recipient
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.ContentView
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.GroupConversation
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.Message
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.SavedMessages
import org.thoughtcrime.securesms.util.DateUtils
import org.thoughtcrime.securesms.util.SearchUtil
import java.util.Locale
import org.thoughtcrime.securesms.home.search.GlobalSearchAdapter.Model.Contact as ContactModel


class GlobalSearchDiff(
    private val oldQuery: String?,
    private val newQuery: String?,
    private val oldData: List<GlobalSearchAdapter.Model>,
    private val newData: List<GlobalSearchAdapter.Model>
) : DiffUtil.Callback() {
    override fun getOldListSize(): Int = oldData.size
    override fun getNewListSize(): Int = newData.size
    override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
        oldData[oldItemPosition] == newData[newItemPosition]

    override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
        oldQuery == newQuery && oldData[oldItemPosition] == newData[newItemPosition]

    override fun getChangePayload(oldItemPosition: Int, newItemPosition: Int): Any? =
        if (oldQuery != newQuery) newQuery
        else null
}

private val BoldStyleFactory = { StyleSpan(Typeface.BOLD) }

fun ContentView.bindQuery(query: String, model: GlobalSearchAdapter.Model) {
    when (model) {
        is ContactModel -> {
            binding.searchResultTitle.text = getHighlight(
                query,
                model.contact.getSearchName()
            )
        }
        is Message -> {
            val textSpannable = SpannableStringBuilder()
            if (model.messageResult.conversationRecipient != model.messageResult.messageRecipient) {
                // group chat, bind
                val text = "${model.messageResult.messageRecipient.getSearchName()}: "
                textSpannable.append(text)
            }
            textSpannable.append(getHighlight(
                    query,
                    model.messageResult.bodySnippet
            ))
            binding.searchResultSubtitle.text = textSpannable
            binding.searchResultSubtitle.isVisible = true
            binding.searchResultTitle.text = model.messageResult.conversationRecipient.toShortString()
        }
        is GroupConversation -> {
            binding.searchResultTitle.text = getHighlight(
                query,
                model.groupRecord.title
            )

            val membersString = model.groupRecord.members.joinToString { address ->
                val recipient = Recipient.from(binding.root.context, address, false)
                recipient.name ?: "${address.serialize().take(4)}...${address.serialize().takeLast(4)}"
            }
            binding.searchResultSubtitle.text = getHighlight(query, membersString)
        }
    }
}

private fun getHighlight(query: String?, toSearch: String): Spannable? {
    return SearchUtil.getHighlightedSpan(Locale.getDefault(), BoldStyleFactory, toSearch, query)
}

fun ContentView.bindModel(query: String?, model: GroupConversation) {
    binding.searchResultProfilePicture.root.isVisible = true
    binding.searchResultSavedMessages.isVisible = false
    binding.searchResultSubtitle.isVisible = model.groupRecord.isClosedGroup
    binding.searchResultTimestamp.isVisible = false
    val threadRecipient = Recipient.from(binding.root.context, Address.fromSerialized(model.groupRecord.encodedId), false)
    binding.searchResultProfilePicture.root.update(threadRecipient)
    val nameString = model.groupRecord.title
    binding.searchResultTitle.text = getHighlight(query, nameString)

    val groupRecipients = model.groupRecord.members.map { Recipient.from(binding.root.context, it, false) }

    val membersString = groupRecipients.joinToString {
        val address = it.address.serialize()
        it.name ?: "${address.take(4)}...${address.takeLast(4)}"
    }
    if (model.groupRecord.isClosedGroup) {
        binding.searchResultSubtitle.text = getHighlight(query, membersString)
    }
}

fun ContentView.bindModel(query: String?, model: ContactModel) {
    binding.searchResultProfilePicture.root.isVisible = true
    binding.searchResultSavedMessages.isVisible = false
    binding.searchResultSubtitle.isVisible = false
    binding.searchResultTimestamp.isVisible = false
    binding.searchResultSubtitle.text = null
    val recipient =
        Recipient.from(binding.root.context, Address.fromSerialized(model.contact.sessionID), false)
    binding.searchResultProfilePicture.root.update(recipient)
    val nameString = model.contact.getSearchName()
    binding.searchResultTitle.text = getHighlight(query, nameString)
}

fun ContentView.bindModel(model: SavedMessages) {
    binding.searchResultSubtitle.isVisible = false
    binding.searchResultTimestamp.isVisible = false
    binding.searchResultTitle.setText(R.string.note_to_self)
    binding.searchResultProfilePicture.root.isVisible = false
    binding.searchResultSavedMessages.isVisible = true
}

fun ContentView.bindModel(query: String?, model: Message) {
    binding.searchResultProfilePicture.root.isVisible = true
    binding.searchResultSavedMessages.isVisible = false
    binding.searchResultTimestamp.isVisible = true
//    val hasUnreads = model.unread > 0
//    binding.unreadCountIndicator.isVisible = hasUnreads
//    if (hasUnreads) {
//        binding.unreadCountTextView.text = model.unread.toString()
//    }
    binding.searchResultTimestamp.text = DateUtils.getDisplayFormattedTimeSpanString(binding.root.context, Locale.getDefault(), model.messageResult.sentTimestampMs)
    binding.searchResultProfilePicture.root.update(model.messageResult.conversationRecipient)
    val textSpannable = SpannableStringBuilder()
    if (model.messageResult.conversationRecipient != model.messageResult.messageRecipient) {
        // group chat, bind
        val text = "${model.messageResult.messageRecipient.getSearchName()}: "
        textSpannable.append(text)
    }
    textSpannable.append(getHighlight(
            query,
            model.messageResult.bodySnippet
    ))
    binding.searchResultSubtitle.text = textSpannable
    binding.searchResultTitle.text = model.messageResult.conversationRecipient.toShortString()
    binding.searchResultSubtitle.isVisible = true
}

fun Recipient.getSearchName(): String = name ?: address.serialize().let { address -> "${address.take(4)}...${address.takeLast(4)}" }

fun Contact.getSearchName(): String =
        if (nickname.isNullOrEmpty()) name ?: "${sessionID.take(4)}...${sessionID.takeLast(4)}"
        else "${name ?: "${sessionID.take(4)}...${sessionID.takeLast(4)}"} ($nickname)"