package bou.amine.apps.readerforselfossv2.android.adapters

import android.app.Activity
import android.content.Context
import android.graphics.Color
import android.widget.TextView
import androidx.recyclerview.widget.RecyclerView
import androidx.viewbinding.ViewBinding
import bou.amine.apps.readerforselfossv2.android.R
import bou.amine.apps.readerforselfossv2.android.utils.openItemUrl
import bou.amine.apps.readerforselfossv2.model.SelfossModel
import bou.amine.apps.readerforselfossv2.repository.Repository
import bou.amine.apps.readerforselfossv2.service.AppSettingsService
import bou.amine.apps.readerforselfossv2.utils.ItemType
import com.google.android.material.snackbar.Snackbar
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.kodein.di.DIAware

abstract class ItemsAdapter<VH : RecyclerView.ViewHolder?> : RecyclerView.Adapter<VH>(), DIAware {
    abstract val items: ArrayList<SelfossModel.Item>
    abstract val repository: Repository
    abstract val binding: ViewBinding
    abstract val appSettingsService: AppSettingsService
    abstract val app: Activity
    abstract val updateHomeItems: (ArrayList<SelfossModel.Item>) -> Unit

    protected val c: Context get() = app.baseContext

    fun updateAllItems(items: ArrayList<SelfossModel.Item>) {
        this.items.clear()
        this.items.addAll(items)
        updateHomeItems(items)
        notifyDataSetChanged()
    }

    private fun unmarkSnackbar(
        item: SelfossModel.Item,
        position: Int,
    ) {
        val s =
            Snackbar
                .make(
                    app.findViewById(R.id.coordLayout),
                    R.string.marked_as_read,
                    Snackbar.LENGTH_LONG,
                )
                .setAction(R.string.undo_string) {
                    unreadItemAtIndex(item, position, false)
                }

        val view = s.view
        val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text)
        tv.setTextColor(Color.WHITE)
        s.show()
    }

    private fun markSnackbar(
        item: SelfossModel.Item,
        position: Int,
    ) {
        val s =
            Snackbar
                .make(
                    app.findViewById(R.id.coordLayout),
                    R.string.marked_as_unread,
                    Snackbar.LENGTH_LONG,
                )
                .setAction(R.string.undo_string) {
                    readItemAtIndex(item, position, false)
                }

        val view = s.view
        val tv: TextView = view.findViewById(com.google.android.material.R.id.snackbar_text)
        tv.setTextColor(Color.WHITE)
        s.show()
    }

    protected fun handleLinkOpening(holderBinding: ViewBinding, position: Int) {
        holderBinding.root.setOnClickListener {
            repository.setReaderItems(items)
            c.openItemUrl(
                position,
                items[position].getLinkDecoded(),
                appSettingsService.isArticleViewerEnabled(),
                app,
            )
        }
    }

    fun handleItemAtIndex(position: Int) {
        if (items[position].unread) {
            readItemAtIndex(items[position], position)
        } else {
            unreadItemAtIndex(items[position], position)
        }
    }

    private fun readItemAtIndex(
        item: SelfossModel.Item,
        position: Int,
        showSnackbar: Boolean = true,
    ) {
        CoroutineScope(Dispatchers.IO).launch {
            repository.markAsRead(item)
        }
        if (repository.displayedItems == ItemType.UNREAD) {
            items.remove(item)
            notifyItemRemoved(position)
            notifyItemRangeChanged(position, itemCount)
            updateHomeItems(items)
        } else {
            notifyItemChanged(position)
        }
        if (showSnackbar) {
            unmarkSnackbar(item, position)
        }
    }

    private fun unreadItemAtIndex(
        item: SelfossModel.Item,
        position: Int,
        showSnackbar: Boolean = true,
    ) {
        CoroutineScope(Dispatchers.IO).launch {
            repository.unmarkAsRead(item)
        }
        notifyItemChanged(position)
        if (showSnackbar) {
            markSnackbar(item, position)
        }
    }

    fun addItemAtIndex(
        item: SelfossModel.Item,
        position: Int,
    ) {
        items.add(position, item)
        notifyItemInserted(position)
        updateHomeItems(items)
    }

    fun addItemsAtEnd(newItems: List<SelfossModel.Item>) {
        val oldSize = items.size
        items.addAll(newItems)
        notifyItemRangeInserted(oldSize, newItems.size)
        updateHomeItems(items)
    }

    override fun getItemCount(): Int = items.size
}
