package com.aletheia.app.ui.qbooks

import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.RecyclerView
import com.aletheia.app.R
import com.aletheia.app.databinding.ItemQbooksBookBinding
import com.aletheia.app.model.QBooksBook
import com.aletheia.app.util.setBookCover

class QBooksCatalogAdapter(
    private val onBookClicked: (QBooksBook) -> Unit,
    private val onDownloadClicked: (QBooksBook) -> Unit
) : RecyclerView.Adapter<QBooksCatalogAdapter.QBooksBookViewHolder>() {

    private val items = mutableListOf<QBooksBook>()

    fun submitList(books: List<QBooksBook>) {
        val oldItems = items.toList()
        val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
            override fun getOldListSize(): Int = oldItems.size
            override fun getNewListSize(): Int = books.size
            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
                oldItems[oldItemPosition].id == books[newItemPosition].id

            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
                oldItems[oldItemPosition].hasSameVisibleContent(books[newItemPosition])
        })

        items.clear()
        items.addAll(books)
        diff.dispatchUpdatesTo(this)
    }

    fun appendDistinct(books: List<QBooksBook>) {
        val existingIds = items.map { it.id }.toHashSet()
        val startIndex = items.size
        val newItems = books.filter { existingIds.add(it.id) }
        if (newItems.isEmpty()) {
            return
        }

        items.addAll(newItems)
        notifyItemRangeInserted(startIndex, newItems.size)
    }

    fun appendOrUpdate(books: List<QBooksBook>) {
        val merged = items.toMutableList()
        books.forEach { book ->
            val index = merged.indexOfFirst { it.id == book.id }
            if (index >= 0) merged[index] = book else merged += book
        }
        submitList(merged)
    }

    fun currentItems(): List<QBooksBook> = items.toList()

    fun updateCover(bookId: String, coverImage: ByteArray) {
        val index = items.indexOfFirst { it.id == bookId }
        if (index < 0) return
        items[index] = items[index].copy(coverImage = coverImage)
        notifyItemChanged(index)
    }

    fun updateBook(book: QBooksBook) {
        val index = items.indexOfFirst { it.id == book.id }
        if (index < 0) return
        items[index] = book
        notifyItemChanged(index)
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): QBooksBookViewHolder {
        val binding = ItemQbooksBookBinding.inflate(LayoutInflater.from(parent.context), parent, false)
        return QBooksBookViewHolder(binding)
    }

    override fun onBindViewHolder(holder: QBooksBookViewHolder, position: Int) {
        holder.bind(items[position])
    }

    override fun getItemCount(): Int = items.size

    inner class QBooksBookViewHolder(
        private val binding: ItemQbooksBookBinding
    ) : RecyclerView.ViewHolder(binding.root) {

        fun bind(book: QBooksBook) {
            val context = binding.root.context
            val formatText = context.getString(R.string.qbooks_format_label, book.format.uppercase())
            binding.bookTitle.text = book.title
            binding.bookAuthor.text = book.author
            binding.bookFormat.text = formatText
            binding.bookCover.setBookCover(book.coverImage, R.drawable.default_cover)
            binding.root.contentDescription = context.getString(
                R.string.a11y_qbooks_book_card,
                book.title,
                book.author,
                formatText
            )
            binding.downloadButton.contentDescription = context.getString(
                R.string.a11y_download_qbooks_book,
                book.title
            )
            binding.root.setOnClickListener { onBookClicked(book) }
            binding.downloadButton.setOnClickListener { onDownloadClicked(book) }
        }
    }

    private fun QBooksBook.hasSameVisibleContent(other: QBooksBook): Boolean =
        title == other.title &&
            author == other.author &&
            format == other.format &&
            coverImage.bytesEqual(other.coverImage)

    private fun ByteArray?.bytesEqual(other: ByteArray?): Boolean = when {
        this === other -> true
        this == null || other == null -> false
        else -> contentEquals(other)
    }
}
