package com.aletheia.app.ui.books

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.ItemQbooksShelfBookBinding
import com.aletheia.app.databinding.ItemQbooksShelfStatusBinding
import com.aletheia.app.model.QBooksBook
import com.aletheia.app.util.setBookCover

class QBooksShelfAdapter(
    private val onBookClicked: (QBooksBook) -> Unit,
    private val onStatusClicked: () -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {

    private val items = mutableListOf<QBooksShelfItem>()

    fun submitBooks(books: List<QBooksBook>) {
        submitItems(books.map(QBooksShelfItem::BookItem))
    }

    fun submitStatus(title: String, detail: String) {
        submitItems(listOf(QBooksShelfItem.StatusItem(title, detail)))
    }

    fun updateCover(bookId: String, coverImage: ByteArray) {
        val index = items.indexOfFirst { item ->
            item is QBooksShelfItem.BookItem && item.book.id == bookId
        }
        if (index < 0) return
        val item = items[index] as QBooksShelfItem.BookItem
        items[index] = item.copy(book = item.book.copy(coverImage = coverImage))
        notifyItemChanged(index)
    }

    fun updateBook(book: QBooksBook) {
        val index = items.indexOfFirst { item ->
            item is QBooksShelfItem.BookItem && item.book.id == book.id
        }
        if (index < 0) return
        items[index] = QBooksShelfItem.BookItem(book)
        notifyItemChanged(index)
    }

    override fun getItemViewType(position: Int): Int = when (items[position]) {
        is QBooksShelfItem.BookItem -> VIEW_TYPE_BOOK
        is QBooksShelfItem.StatusItem -> VIEW_TYPE_STATUS
    }

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
        val inflater = LayoutInflater.from(parent.context)
        return when (viewType) {
            VIEW_TYPE_BOOK -> BookViewHolder(ItemQbooksShelfBookBinding.inflate(inflater, parent, false))
            VIEW_TYPE_STATUS -> StatusViewHolder(ItemQbooksShelfStatusBinding.inflate(inflater, parent, false))
            else -> error("Unsupported QBooks shelf item view type: $viewType")
        }
    }

    override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
        when (val item = items[position]) {
            is QBooksShelfItem.BookItem -> (holder as BookViewHolder).bind(item.book)
            is QBooksShelfItem.StatusItem -> (holder as StatusViewHolder).bind(item)
        }
    }

    override fun getItemCount(): Int = items.size

    private fun submitItems(newItems: List<QBooksShelfItem>) {
        val oldItems = items.toList()
        val diff = DiffUtil.calculateDiff(object : DiffUtil.Callback() {
            override fun getOldListSize(): Int = oldItems.size
            override fun getNewListSize(): Int = newItems.size

            override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
                oldItems[oldItemPosition].stableKey == newItems[newItemPosition].stableKey

            override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean =
                oldItems[oldItemPosition] == newItems[newItemPosition]
        })
        items.clear()
        items.addAll(newItems)
        diff.dispatchUpdatesTo(this)
    }

    private inner class BookViewHolder(
        private val binding: ItemQbooksShelfBookBinding
    ) : RecyclerView.ViewHolder(binding.root) {

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

    private inner class StatusViewHolder(
        private val binding: ItemQbooksShelfStatusBinding
    ) : RecyclerView.ViewHolder(binding.root) {

        fun bind(item: QBooksShelfItem.StatusItem) {
            binding.statusTitle.text = item.title
            binding.statusDetail.text = item.detail
            binding.root.contentDescription = "${item.title}. ${item.detail}"
            binding.root.setOnClickListener { onStatusClicked() }
        }
    }

    private sealed class QBooksShelfItem {
        abstract val stableKey: String

        data class BookItem(val book: QBooksBook) : QBooksShelfItem() {
            override val stableKey: String = "book:${book.id}"
        }

        data class StatusItem(val title: String, val detail: String) : QBooksShelfItem() {
            override val stableKey: String = "status"
        }
    }

    private companion object {
        const val VIEW_TYPE_BOOK = 1
        const val VIEW_TYPE_STATUS = 2
    }
}
