/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

package org.mozilla.focus.session.ui

import androidx.annotation.DrawableRes
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.view.isVisible
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.browser.state.state.TabSessionState
import org.mozilla.focus.R
import org.mozilla.focus.databinding.ItemSessionBinding
import org.mozilla.focus.ext.beautifyUrl
import java.lang.ref.WeakReference
import mozilla.components.ui.icons.R as iconsR

/**
 * [RecyclerView.ViewHolder] implementation for displaying a tab session or action items
 * (like "Add New Tab" or "Close All Tabs") in the tabs tray.
 *
 * @param binding The [ItemSessionBinding] for the layout of this view holder.
 */
class TabViewHolder(
    private val binding: ItemSessionBinding,
) : RecyclerView.ViewHolder(binding.root) {

    private var tabReference: WeakReference<TabSessionState> = WeakReference<TabSessionState>(null)

    /**
     * Binds a given tab to the view holder or adds additional options if tab is null.
     *
     * @param tab The tab session state to bind. Can be null.
     * @param isCurrentSession Indicates if the tab is the current session.
     * @param selectSession Function to call when the tab is selected.
     * @param closeSession Function to call when the tab is closed.
     * @param closeOtherSessions Function to call when closing all other tabs.
     * @param addNewTab Function to call when adding a new tab.
     * @param isCloseAllItem Indicates if this item should represent the "Close All Tabs" action.
     * @param isAddNewTabItem Indicates if this item should represent the "Add New Tab" action.
     */

    fun bind(
        tab: TabSessionState?,
        isCurrentSession: Boolean,
        selectSession: (TabSessionState) -> Unit,
        closeSession: (TabSessionState) -> Unit,
        closeOtherSessions: () -> Unit = {},
        addNewTab: () -> Unit,
        isCloseAllItem: Boolean,
        isAddNewTabItem: Boolean,
    ) {
        val drawable = if (isCurrentSession) {
            R.drawable.background_list_item_current_session
        } else {
            R.drawable.background_list_item_session
        }

        when {
            tab != null -> {
                bindTab(tab, drawable, selectSession, closeSession)
            }
            isCloseAllItem -> {
                bindCloseAllTabs(drawable, closeOtherSessions)
            }
            isAddNewTabItem -> {
                bindNewTabItem(drawable, addNewTab)
            }
        }
    }

    /**
     * Binds the given tab to the view holder.
     *
     * @param tab The tab session state to bind.
     * @param drawable The background drawable resource ID.
     * @param selectSession Function to call when the tab is selected.
     * @param closeSession Function to call when the tab is closed.
     */
    private fun bindTab(
        tab: TabSessionState,
        @DrawableRes drawable: Int,
        selectSession: (TabSessionState) -> Unit,
        closeSession: (TabSessionState) -> Unit,
    ) {
        tabReference = WeakReference(tab)

        val title = tab.content.title.ifEmpty { tab.content.url.beautifyUrl() }

        binding.sessionItem.setBackgroundResource(drawable)
        binding.sessionTitle.apply {
            setCompoundDrawablesWithIntrinsicBounds(iconsR.drawable.mozac_ic_link_24, 0, 0, 0)
            text = title
            setOnClickListener {
                val clickedTab = tabReference.get() ?: return@setOnClickListener
                selectSession(clickedTab)
            }
        }

        binding.closeButton.setOnClickListener {
            val clickedTab = tabReference.get() ?: return@setOnClickListener
            closeSession(clickedTab)
        }
    }

    /**
     * Binds the view holder to close all other tabs.
     *
     * @param drawable The background drawable resource ID.
     * @param closeOtherSessions Function to call when closing all other tabs.
     */
    private fun bindCloseAllTabs(
        @DrawableRes drawable: Int,
        closeOtherSessions: () -> Unit,
    ) {
        binding.sessionItem.setBackgroundResource(drawable)

        val drawableWidth =
            AppCompatResources.getDrawable(binding.root.context, iconsR.drawable.mozac_ic_link_24)?.intrinsicWidth ?: 0

        binding.sessionTitle.apply {
            text = binding.root.context.getString(R.string.tabs_tray_action_erase_other)
            setCompoundDrawablesWithIntrinsicBounds(0, 0, 0, 0)

            setPaddingRelative(
                paddingStart + drawableWidth + compoundDrawablePadding,
                paddingTop,
                paddingRight,
                paddingBottom,
            )

            setOnClickListener {
                closeOtherSessions.invoke()
            }
        }

        binding.closeButton.isVisible = false
    }

    private fun bindNewTabItem(drawable: Int, addNewTab: () -> Unit) {
        binding.sessionItem.setBackgroundResource(drawable)

        AppCompatResources.getDrawable(binding.root.context, R.drawable.ic_tab_new)?.intrinsicWidth ?: 0

        binding.sessionTitle.apply {
            text = binding.root.context.getString(R.string.tabs_tray_action_add_new_tab)
            setCompoundDrawablesWithIntrinsicBounds(R.drawable.ic_tab_new, 0, 0, 0)

            setOnClickListener {
                addNewTab.invoke()
            }
        }

        binding.closeButton.isVisible = false
    }
}
