package bou.amine.apps.readerforselfossv2.android

import android.content.Intent
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.graphics.drawable.GradientDrawable
import android.net.Uri
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import android.widget.ImageView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.core.view.doOnNextLayout
import androidx.drawerlayout.widget.DrawerLayout
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.*
import androidx.work.Constraints
import androidx.work.ExistingPeriodicWorkPolicy
import androidx.work.PeriodicWorkRequestBuilder
import androidx.work.WorkManager
import bou.amine.apps.readerforselfossv2.android.adapters.ItemCardAdapter
import bou.amine.apps.readerforselfossv2.android.adapters.ItemListAdapter
import bou.amine.apps.readerforselfossv2.android.adapters.ItemsAdapter
import bou.amine.apps.readerforselfossv2.android.background.LoadingWorker
import bou.amine.apps.readerforselfossv2.android.databinding.ActivityHomeBinding
import bou.amine.apps.readerforselfossv2.android.settings.SettingsActivity
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.maybeShow
import bou.amine.apps.readerforselfossv2.android.utils.bottombar.removeBadge
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 bou.amine.apps.readerforselfossv2.utils.getHtmlDecoded
import bou.amine.apps.readerforselfossv2.utils.getIcon
import bou.amine.apps.readerforselfossv2.utils.longHash
import com.ashokvarma.bottomnavigation.BottomNavigationBar
import com.ashokvarma.bottomnavigation.BottomNavigationItem
import com.ashokvarma.bottomnavigation.TextBadgeItem
import com.bumptech.glide.Glide
import com.bumptech.glide.request.RequestOptions
import com.mikepenz.aboutlibraries.LibsBuilder
import com.mikepenz.materialdrawer.holder.BadgeStyle
import com.mikepenz.materialdrawer.holder.ColorHolder
import com.mikepenz.materialdrawer.holder.StringHolder
import com.mikepenz.materialdrawer.model.DividerDrawerItem
import com.mikepenz.materialdrawer.model.PrimaryDrawerItem
import com.mikepenz.materialdrawer.model.SecondaryDrawerItem
import com.mikepenz.materialdrawer.model.interfaces.*
import com.mikepenz.materialdrawer.util.AbstractDrawerImageLoader
import com.mikepenz.materialdrawer.util.DrawerImageLoader
import com.mikepenz.materialdrawer.util.addStickyFooterItem
import com.mikepenz.materialdrawer.util.updateBadge
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import org.kodein.di.DIAware
import org.kodein.di.android.closestDI
import org.kodein.di.instance
import org.matomo.sdk.Tracker
import org.matomo.sdk.extra.TrackHelper
import java.security.MessageDigest
import java.util.concurrent.TimeUnit


class HomeActivity : AppCompatActivity(), SearchView.OnQueryTextListener, DIAware {

    private val DRAWER_ID_TAGS = 100101L
    private val DRAWER_ID_HIDDEN_TAGS = 101100L
    private val DRAWER_ID_SOURCES = 100110L
    private val DRAWER_ID_FILTERS = 100111L

    private var items: ArrayList<SelfossModel.Item> = ArrayList()

    private var elementsShown: ItemType = ItemType.UNREAD
    private var lastFetchDone: Boolean = false

    private lateinit var tabNewBadge: TextBadgeItem
    private lateinit var tabArchiveBadge: TextBadgeItem
    private lateinit var tabStarredBadge: TextBadgeItem
    private var offset: Int = 0
    private var firstVisible: Int = 0
    private lateinit var recyclerViewScrollListener: RecyclerView.OnScrollListener
    private lateinit var binding: ActivityHomeBinding

    private var recyclerAdapter: RecyclerView.Adapter<*>? = null

    private var fromTabShortcut: Boolean = false

    private lateinit var tagsBadge: Map<Long, Int>

    private val settingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
        appSettingsService.refreshUserSettings()
    }

    override val di by closestDI()
    private val repository : Repository by instance()
    private val appSettingsService : AppSettingsService by instance()
    private val tracker : Tracker by instance()


    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityHomeBinding.inflate(layoutInflater)
        val view = binding.root

        TrackHelper.track().screen("/home").with(tracker)

        fromTabShortcut =  intent.getIntExtra("shortcutTab", -1) != -1
        repository.offlineOverride =  intent.getBooleanExtra("startOffline", false)

        if (fromTabShortcut) {
            elementsShown = ItemType.fromInt(intent.getIntExtra("shortcutTab", ItemType.UNREAD.position))
        }

        setContentView(view)

        setSupportActionBar(binding.toolBar)
        supportActionBar?.setDisplayHomeAsUpEnabled(true)
        supportActionBar?.setHomeButtonEnabled(true)
        val mDrawerToggle = ActionBarDrawerToggle(this, binding.drawerContainer, binding.toolBar, R.string.material_drawer_open, R.string.material_drawer_close)
        binding.drawerContainer.addDrawerListener(mDrawerToggle)
        mDrawerToggle.syncState()

        handleBottomBar()
        initDrawer()

        handleSwipeRefreshLayout()


        if (appSettingsService.isItemCachingEnabled()) {
            CoroutineScope(Dispatchers.Main).launch {
                repository.tryToCacheItemsAndGetNewOnes()
            }
        }
    }

    private fun handleSwipeRefreshLayout() {
        binding.swipeRefreshLayout.setColorSchemeResources(
            R.color.refresh_progress_1,
            R.color.refresh_progress_2,
            R.color.refresh_progress_3
        )
        binding.swipeRefreshLayout.setOnRefreshListener {
            repository.offlineOverride = false
            lastFetchDone = false
            handleDrawerItems()
            CoroutineScope(Dispatchers.Main).launch {
                getElementsAccordingToTab()
                binding.swipeRefreshLayout.isRefreshing = false
            }
        }

        val simpleItemTouchCallback =
            object : ItemTouchHelper.SimpleCallback(
                0,
                ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT
            ) {
                override fun getSwipeDirs(
                    recyclerView: RecyclerView,
                    viewHolder: RecyclerView.ViewHolder
                ): Int =
                    if (elementsShown == ItemType.STARRED) {
                        0
                    } else {
                        super.getSwipeDirs(
                            recyclerView,
                            viewHolder
                        )
                    }

                override fun onMove(
                    recyclerView: RecyclerView,
                    viewHolder: RecyclerView.ViewHolder,
                    target: RecyclerView.ViewHolder
                ): Boolean = false

                override fun onSwiped(viewHolder: RecyclerView.ViewHolder, swipeDir: Int) {
                    val position = viewHolder.bindingAdapterPosition
                    val i = items.elementAtOrNull(position)

                    if (i != null) {
                        val adapter = binding.recyclerView.adapter as ItemsAdapter<*>

                        adapter.handleItemAtIndex(position)

                        val tagHashes = i.tags.map { it.longHash() }
                        tagsBadge = tagsBadge.map {
                            if (tagHashes.contains(it.key)) {
                                (it.key to (it.value - 1))
                            } else {
                                (it.key to it.value)
                            }
                        }.toMap()
                        reloadTagsBadges()

                        // Just load everythin
                        if (items.size <= 0) {
                            getElementsAccordingToTab()
                        }
                    } else {
                        Toast.makeText(
                            this@HomeActivity,
                            "Found null when swiping at positon $position.",
                            Toast.LENGTH_LONG
                        ).show()
                    }
                }
            }

        ItemTouchHelper(simpleItemTouchCallback).attachToRecyclerView(binding.recyclerView)
    }

    private fun updateBottomBarBadgeCount(badge: TextBadgeItem, count: Int) {
        if (count > 0) {
            badge
                .setText(count.toString())
                .maybeShow()
        } else {
            badge.removeBadge()
        }
    }

    private fun handleBottomBar() {

        tabNewBadge = TextBadgeItem()
            .setText("")
            .setHideOnSelect(false).hide(false)
        tabArchiveBadge = TextBadgeItem()
            .setText("")
            .setHideOnSelect(false).hide(false)
        tabStarredBadge = TextBadgeItem()
            .setText("")
            .setHideOnSelect(false).hide(false)

        if (appSettingsService.isDisplayUnreadCountEnabled()) {
            lifecycleScope.launch {
                repository.badgeUnread.collect {
                    updateBottomBarBadgeCount(tabNewBadge, it)
                }
            }
        }

        if (appSettingsService.isDisplayAllCountEnabled()) {
            lifecycleScope.launch {
                repository.badgeAll.collect {
                    updateBottomBarBadgeCount(tabArchiveBadge, it)
                }
            }

            lifecycleScope.launch {
                repository.badgeStarred.collect {
                    updateBottomBarBadgeCount(tabStarredBadge, it)
                }
            }
        }

        val tabNew =
            BottomNavigationItem(
                R.drawable.ic_tab_fiber_new_black_24dp,
                getString(R.string.tab_new)
            )
                .setBadgeItem(tabNewBadge)
        val tabArchive =
            BottomNavigationItem(
                R.drawable.ic_tab_archive_black_24dp,
                getString(R.string.tab_read)
            )
                .setBadgeItem(tabArchiveBadge)
        val tabStarred =
            BottomNavigationItem(
                R.drawable.ic_tab_favorite_black_24dp,
                getString(R.string.tab_favs)
            ).setActiveColorResource(R.color.pink)
                .setBadgeItem(tabStarredBadge)

        binding.bottomBar
            .addItem(tabNew)
            .addItem(tabArchive)
            .addItem(tabStarred)
            .setFirstSelectedPosition(0)
            .initialise()
        binding.bottomBar.setMode(BottomNavigationBar.MODE_SHIFTING)

        if (fromTabShortcut) {
            binding.bottomBar.selectTab(elementsShown.position - 1)
        }
    }

    override fun onResume() {
        super.onResume()

        handleDrawerItems()

        reloadLayoutManager()

        if (appSettingsService.isInfiniteLoadingEnabled()) {
            handleInfiniteScroll()
        } else {
            binding.recyclerView.setHasFixedSize(true)
        }

        handleBottomBarActions()

        handleGDPRDialog(appSettingsService.settings.getBoolean("GDPR_shown", false))

        handleRecurringTask()

        CoroutineScope(Dispatchers.Main).launch {
            repository.handleDBActions()
        }

        getElementsAccordingToTab()
    }


    private fun handleGDPRDialog(GDPRShown: Boolean) {
        val messageDigest: MessageDigest = MessageDigest.getInstance("SHA-256")
        messageDigest.update(appSettingsService.getBaseUrl().toByteArray())
        if (!GDPRShown) {
            val alertDialog = AlertDialog.Builder(this).create()
            alertDialog.setTitle(getString(R.string.gdpr_dialog_title))
            alertDialog.setMessage(getString(R.string.gdpr_dialog_message))
            alertDialog.setButton(
                AlertDialog.BUTTON_NEUTRAL,
                "OK"
            ) { dialog, _ ->
                appSettingsService.settings.putBoolean("GDPR_shown", true)
                dialog.dismiss()
            }
            alertDialog.show()
        }
    }

    private fun initDrawer() {
        DrawerImageLoader.init(object : AbstractDrawerImageLoader() {
            override fun set(imageView: ImageView, uri: Uri, placeholder: Drawable, tag: String?) {
                Glide.with(this@HomeActivity)
                    .asBitmap()
                    .load(uri)
                    .apply(RequestOptions()
                        .placeholder(R.mipmap.ic_launcher)
                        .fallback(R.mipmap.ic_launcher)
                        .fitCenter())
                    .into(imageView)
            }

            override fun cancel(imageView: ImageView) {
                Glide.with(this@HomeActivity).clear(imageView)
            }
        })

        val drawerListener = object : DrawerLayout.DrawerListener {
            override fun onDrawerSlide(drawerView: View, slideOffset: Float) {
                // We do nothing
            }

            override fun onDrawerOpened(drawerView: View) {
                binding.bottomBar.hide()
            }

            override fun onDrawerClosed(drawerView: View) {
                binding.bottomBar.show()
            }

            override fun onDrawerStateChanged(newState: Int) {
                // We do nothing
            }

        }

        binding.drawerContainer.addDrawerListener(drawerListener)

        // Sticky items
        addStickyPrimaryItem(R.string.drawer_report_bug, R.drawable.ic_bug_report_black_24dp) { _, _, _ ->
            val browserIntent =
                Intent(Intent.ACTION_VIEW, Uri.parse(AppSettingsService.trackerUrl))
            startActivity(browserIntent)
            false
        }
        addStickyPrimaryItem(R.string.title_activity_settings, R.drawable.ic_settings_black_24dp) { _, _, _ ->
            settingsLauncher.launch(Intent(this, SettingsActivity::class.java))
            false
        }
    }

    private fun addStickyPrimaryItem(name: Int, icon: Int, clickListener: ((v: View?, item: IDrawerItem<*>, position: Int) -> Boolean)?) {
        binding.mainDrawer.addStickyFooterItem(
            PrimaryDrawerItem().apply {
                nameRes = name
                iconRes = icon
                isIconTinted = true
                onDrawerItemClickListener = clickListener
            })
    }

    private fun handleDrawerItems() {
        tagsBadge = emptyMap()
        binding.mainDrawer.itemAdapter.add(
            PrimaryDrawerItem().apply {
                nameRes = R.string.drawer_loading
                isSelectable = false
            }
        )

        CoroutineScope(Dispatchers.IO).launch {
            val tags = repository.getTags()
            val sources = repository.getSources()
            runOnUiThread {
                handleDrawerData(tags, sources)
            }
        }
    }

    private fun handleDrawerData(tags: List<SelfossModel.Tag>, sources: List<SelfossModel.Source>) {
        binding.mainDrawer.itemAdapter.clear()

        // Filters title with clear action
        secondaryItem(withDivider = false, R.string.drawer_item_filters, DRAWER_ID_FILTERS, R.string.drawer_action_clear) { _,_,_ ->
            repository.sourceFilter = null
            repository.tagFilter = null
            binding.mainDrawer.setSelectionAtPosition(-1)
            getElementsAccordingToTab()
            fetchOnEmptyList()
            false
        }

        // Hidden tags
        if (tags.isNotEmpty() && appSettingsService.getHiddenTags().isNotEmpty()) {
            secondaryItem(
                withDivider = true,
                R.string.drawer_item_hidden_tags,
                DRAWER_ID_HIDDEN_TAGS
            )
            handleHiddenTags(tags)
        }

        // Tags
        secondaryItem(withDivider = true, R.string.drawer_item_tags, DRAWER_ID_TAGS)
        if (tags.isEmpty()) {
            binding.mainDrawer.itemAdapter.add(
                SecondaryDrawerItem()
                    .apply { nameRes = R.string.drawer_error_loading_tags; isSelectable = false }
            )
        } else {
            handleTags(tags)
        }

        // Sources
        secondaryItem(withDivider = true, R.string.drawer_item_sources, DRAWER_ID_SOURCES, R.string.drawer_action_edit) { v, _, _ ->
            startActivity(Intent(v!!.context, SourcesActivity::class.java))
            false
        }
        if (sources.isEmpty()) {
            binding.mainDrawer.itemAdapter.add(
                SecondaryDrawerItem().apply {
                    nameRes = R.string.drawer_error_loading_sources
                    isSelectable = false
                }
            )
        } else {
            handleSources(sources)
        }

        // About action
        binding.mainDrawer.itemAdapter.add(
            DividerDrawerItem(),
            PrimaryDrawerItem().apply {
                nameRes = R.string.action_about
                isSelectable = false
                iconRes = R.drawable.ic_info_outline_white_24dp
                isIconTinted = true
                onDrawerItemClickListener = { _,_,_ ->
                    LibsBuilder()
                        .withAboutIconShown(true)
                        .withAboutVersionShown(true)
                        .start(this@HomeActivity)
                    false
                }
            }
        )
    }

    private fun secondaryItem(withDivider: Boolean, name: Int, id: Long, badgeId: Int? = null, clickListener: ((v: View?, item: IDrawerItem<*>, position: Int) -> Boolean)? = null) {
        if (withDivider) {
            binding.mainDrawer.itemAdapter.add(DividerDrawerItem())
        }

        binding.mainDrawer.itemAdapter.add(
            SecondaryDrawerItem().apply {
                nameRes = name
                identifier = id
                isSelectable = false
                if (badgeId != null) {
                    badgeRes = badgeId
                }
                onDrawerItemClickListener = clickListener
            }
        )
    }

    private fun createDrawerItem(it: SelfossModel.Tag) {
        val gd = GradientDrawable()
        val gdColor = try {
            Color.parseColor(it.color)
        } catch (e: IllegalArgumentException) {
            e.sendSilentlyWithAcraWithName("color issue " + it.color)
            resources.getColor(R.color.colorPrimary)
        }
        gd.setColor(gdColor)
        gd.shape = GradientDrawable.RECTANGLE
        gd.setSize(30, 30)
        gd.cornerRadius = 30F

        val drawerItem = PrimaryDrawerItem()
            .apply {
                nameText = it.tag.getHtmlDecoded()
                identifier = it.tag.longHash()
                iconDrawable = gd
                badgeStyle = BadgeStyle().apply {
                    textColor = ColorHolder.fromColor(Color.WHITE)
                    color = ColorHolder.fromColor(resources.getColor(R.color.colorAccent))
                }
                onDrawerItemClickListener = { _, _, _ ->
                    repository.tagFilter = it
                    repository.sourceFilter = null
                    getElementsAccordingToTab()
                    fetchOnEmptyList()
                    false
                }
            }
        if (it.unread > 0) {
            drawerItem.badgeText = it.unread.toString()
        }

        binding.mainDrawer.itemAdapter.add(drawerItem)
    }

    private fun handleTags(tags: List<SelfossModel.Tag>) {
        val filteredTags = tags
            .filterNot { appSettingsService.getHiddenTags().contains(it.tag) }
            .sortedBy { it.tag }
        createTagItems(filteredTags)
    }

    private fun handleHiddenTags(tags: List<SelfossModel.Tag>) {
        val filteredHiddenTags: List<SelfossModel.Tag> =
            tags.filter { appSettingsService.getHiddenTags().contains(it.tag) }
        createTagItems(filteredHiddenTags)
    }

    private fun createTagItems(tags: List<SelfossModel.Tag>) {
        tagsBadge = tags.associate {
            createDrawerItem(it)

            (it.tag.longHash() to it.unread)
        }
    }

    private fun handleSources(sources: List<SelfossModel.Source>) {
        for (source in sources) {
            val item = PrimaryDrawerItem().apply {
                nameText = source.title.getHtmlDecoded()
                identifier = source.id.toLong()
                iconUrl = source.getIcon(repository.baseUrl)
                onDrawerItemClickListener = { _,_,_ ->
                    repository.sourceFilter = source
                    repository.tagFilter = null
                    getElementsAccordingToTab()
                    fetchOnEmptyList()
                    false
                }
            }
            binding.mainDrawer.itemAdapter.add(item)
        }
    }

    private fun reloadLayoutManager() {
        val currentManager = binding.recyclerView.layoutManager
        val layoutManager: RecyclerView.LayoutManager

        // This will only update the layout manager if settings changed
        when (currentManager) {
            is StaggeredGridLayoutManager ->
                if (!appSettingsService.isCardViewEnabled()) {
                    layoutManager = GridLayoutManager(
                        this,
                        calculateNoOfColumns()
                    )
                    binding.recyclerView.layoutManager = layoutManager
                }
            is GridLayoutManager ->
                if (appSettingsService.isCardViewEnabled()) {
                    layoutManager = StaggeredGridLayoutManager(
                        calculateNoOfColumns(),
                        StaggeredGridLayoutManager.VERTICAL
                    )
                    layoutManager.gapStrategy =
                            StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
                    binding.recyclerView.layoutManager = layoutManager
                }
            else ->
                if (currentManager == null) {
                    if (!appSettingsService.isCardViewEnabled()) {
                        layoutManager = GridLayoutManager(
                            this,
                            calculateNoOfColumns()
                        )
                        binding.recyclerView.layoutManager = layoutManager
                    } else {
                        layoutManager = StaggeredGridLayoutManager(
                            calculateNoOfColumns(),
                            StaggeredGridLayoutManager.VERTICAL
                        )
                        layoutManager.gapStrategy =
                                StaggeredGridLayoutManager.GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS
                        binding.recyclerView.layoutManager = layoutManager
                    }
                }
        }
    }

    private fun handleBottomBarActions() {
        binding.bottomBar.setTabSelectedListener(object : BottomNavigationBar.OnTabSelectedListener {
            override fun onTabUnselected(position: Int) = Unit

            override fun onTabReselected(position: Int) {

                when (val layoutManager = binding.recyclerView.adapter) {
                    is StaggeredGridLayoutManager ->
                        if (layoutManager.findFirstCompletelyVisibleItemPositions(null)[0] == 0) {
                            getElementsAccordingToTab()
                        } else {
                            layoutManager.scrollToPositionWithOffset(0, 0)
                        }
                    is GridLayoutManager ->
                        if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
                            getElementsAccordingToTab()
                        } else {
                            layoutManager.scrollToPositionWithOffset(0, 0)
                        }
                    else -> Unit
                }
            }

            override fun onTabSelected(position: Int) {
                offset = 0
                lastFetchDone = false

                elementsShown = ItemType.fromInt(position + 1)
                getElementsAccordingToTab()
                binding.recyclerView.scrollToPosition(0)

                fetchOnEmptyList()
            }
        })
    }

    private fun fetchOnEmptyList() {
        binding.recyclerView.doOnNextLayout {
            // TODO: do if last element (or is empty ?)
            getElementsAccordingToTab(true)
        }
    }

    private fun handleInfiniteScroll() {
        recyclerViewScrollListener = object : RecyclerView.OnScrollListener() {
            override fun onScrolled(localRecycler: RecyclerView, dx: Int, dy: Int) {
                if (dy > 0) {
                    val lastVisibleItem = getLastVisibleItem()

                    if (lastVisibleItem == (items.size - 1) && items.size < maxItemNumber()) {
                        getElementsAccordingToTab(appendResults = true)
                    }
                }
            }
        }

        binding.recyclerView.clearOnScrollListeners()
        binding.recyclerView.addOnScrollListener(recyclerViewScrollListener)
    }

    private fun getLastVisibleItem() : Int {
        return when (val manager = binding.recyclerView.layoutManager) {
            is StaggeredGridLayoutManager -> manager.findLastCompletelyVisibleItemPositions(
                null
            ).last()
            is GridLayoutManager -> manager.findLastCompletelyVisibleItemPosition()
            else -> 0
        }
    }

    private fun mayBeEmpty() =
        if (items.isEmpty()) {
            binding.emptyText.visibility = View.VISIBLE
        } else {
            binding.emptyText.visibility = View.GONE
        }

    private fun getElementsAccordingToTab(
        appendResults: Boolean = false
    ) {
        offset = if (appendResults && items.size > 0) {
            items.size - 1
        } else {
            0
        }
        firstVisible = if (appendResults) firstVisible else 0

        getItems(appendResults, elementsShown)
    }

    private fun getItems(appendResults: Boolean, itemType: ItemType) {
        CoroutineScope(Dispatchers.Main).launch {
            binding.swipeRefreshLayout.isRefreshing = true
            repository.displayedItems = itemType
            items = if (appendResults) {
                repository.getOlderItems()
            } else {
                repository.getNewerItems()
            }
            binding.swipeRefreshLayout.isRefreshing = false
            handleListResult()
        }
    }

    private fun handleListResult(appendResults: Boolean = false) {
        if (appendResults) {
            val oldManager = binding.recyclerView.layoutManager
            firstVisible = when (oldManager) {
                is StaggeredGridLayoutManager ->
                    oldManager.findFirstCompletelyVisibleItemPositions(null).last()
                is GridLayoutManager ->
                    oldManager.findFirstCompletelyVisibleItemPosition()
                else -> 0
            }
        }

        if (recyclerAdapter == null) {
            if (appSettingsService.isCardViewEnabled()) {
                recyclerAdapter =
                        ItemCardAdapter(
                            this,
                            items,
                        ) {
                            updateItems(it)
                        }
            } else {
                recyclerAdapter =
                        ItemListAdapter(
                            this,
                            items,
                        ) {
                            updateItems(it)
                        }

                binding.recyclerView.addItemDecoration(
                    DividerItemDecoration(
                        this@HomeActivity,
                        DividerItemDecoration.VERTICAL
                    )
                )
            }
            binding.recyclerView.adapter = recyclerAdapter
        } else {
                (recyclerAdapter as ItemsAdapter<*>).updateAllItems(items)
        }

        reloadBadges()
        mayBeEmpty()
    }

    private fun reloadBadges() {
        if (appSettingsService.isDisplayUnreadCountEnabled() || appSettingsService.isDisplayAllCountEnabled()) {
            CoroutineScope(Dispatchers.IO).launch {
                repository.reloadBadges()
            }
        }
    }

    private fun reloadTagsBadges() {
        tagsBadge.forEach {
            binding.mainDrawer.updateBadge(it.key, StringHolder(it.value.toString()))
        }
        binding.mainDrawer.resetDrawerContent()
    }

    private fun calculateNoOfColumns(): Int {
        val displayMetrics = resources.displayMetrics
        val dpWidth = displayMetrics.widthPixels / displayMetrics.density
        return (dpWidth / 300).toInt()
    }

    override fun onQueryTextChange(p0: String?): Boolean {
        if (p0.isNullOrBlank()) {
            repository.searchFilter = null
            getElementsAccordingToTab()
            fetchOnEmptyList()
        }
        return false
    }

    override fun onQueryTextSubmit(p0: String?): Boolean {
        repository.searchFilter = p0
        getElementsAccordingToTab()
        fetchOnEmptyList()
        return false
    }

    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        val inflater = menuInflater
        inflater.inflate(R.menu.home_menu, menu)

        val searchItem = menu.findItem(R.id.action_search)
        val searchView = searchItem.getActionView() as SearchView
        searchView.setOnQueryTextListener(this)

        return true
    }

    private fun needsConfirmation(titleRes: Int, messageRes: Int, doFn: () -> Unit) {
        AlertDialog.Builder(this@HomeActivity)
            .setMessage(messageRes)
            .setTitle(titleRes)
            .setPositiveButton(android.R.string.ok) { _, _ -> doFn() }
            .setNegativeButton(android.R.string.cancel) { _, _ -> }
            .create()
            .show()
    }

    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.refresh -> {
                needsConfirmation(R.string.menu_home_refresh, R.string.refresh_dialog_message) {
                    Toast.makeText(this, R.string.refresh_in_progress, Toast.LENGTH_SHORT).show()
                    // TODO: Use Dispatchers.IO
                    CoroutineScope(Dispatchers.Main).launch {
                        val updatedRemote = repository.updateRemote()
                        if (updatedRemote) {
                            // TODO: Send toast messages from the repository
                            Toast.makeText(
                                this@HomeActivity,
                                R.string.refresh_success_response, Toast.LENGTH_LONG
                            )
                                .show()
                        } else {
                            Toast.makeText(
                                this@HomeActivity,
                                R.string.refresh_failer_message,
                                Toast.LENGTH_SHORT
                            ).show()
                        }
                    }
                }
                return true
            }
            R.id.readAll -> {
                if (elementsShown == ItemType.UNREAD) {
                    needsConfirmation(R.string.readAll, R.string.markall_dialog_message) {
                        binding.swipeRefreshLayout.isRefreshing = true

                        CoroutineScope(Dispatchers.Main).launch {
                            val success = repository.markAllAsRead(items)
                            if (success) {
                                Toast.makeText(
                                    this@HomeActivity,
                                    R.string.all_posts_read,
                                    Toast.LENGTH_SHORT
                                ).show()
                                tabNewBadge.removeBadge()

                                handleDrawerItems()

                                getElementsAccordingToTab()
                            } else {
                                Toast.makeText(
                                    this@HomeActivity,
                                    R.string.all_posts_not_read,
                                    Toast.LENGTH_SHORT
                                ).show()
                            }
                            handleListResult()
                            binding.swipeRefreshLayout.isRefreshing = false
                        }
                    }
                }
                return true
            }
            R.id.action_disconnect -> {
                CoroutineScope(Dispatchers.Main).launch {
                    repository.logout()
                }
                val intent = Intent(this, LoginActivity::class.java)
                this.startActivity(intent)
                this@HomeActivity.finish()
                return true
            }
            else -> return super.onOptionsItemSelected(item)
        }
    }

    private fun maxItemNumber(): Int =
        when (elementsShown) {
            ItemType.UNREAD -> repository.badgeUnread.value
            ItemType.ALL -> repository.badgeAll.value
            ItemType.STARRED -> repository.badgeStarred.value
            else -> repository.badgeUnread.value // if !elementsShown then unread are fetched.
        }

    private fun updateItems(adapterItems: ArrayList<SelfossModel.Item>) {
        items = adapterItems
    }

    private fun handleRecurringTask() {
        if (appSettingsService.isPeriodicRefreshEnabled()) {
            val myConstraints = Constraints.Builder()
                .setRequiresBatteryNotLow(true)
                .setRequiresCharging(appSettingsService.isRefreshWhenChargingOnlyEnabled())
                .setRequiresStorageNotLow(true)
                .build()

            val backgroundWork =
                PeriodicWorkRequestBuilder<LoadingWorker>(appSettingsService.getRefreshMinutes(), TimeUnit.MINUTES)
                    .setConstraints(myConstraints)
                    .addTag("selfoss-loading")
                    .build()

            WorkManager.getInstance(baseContext).enqueueUniquePeriodicWork("selfoss-loading", ExistingPeriodicWorkPolicy.KEEP, backgroundWork)
        }
    }
}

