/* 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.fenix.library.bookmarks

import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.RecyclerView
import mozilla.components.concept.storage.BookmarkNodeType
import mozilla.components.support.ktx.android.content.getColorFromAttr
import mozilla.components.support.ktx.android.content.getDrawableWithTint
import mozilla.components.support.ktx.android.util.dpToPx
import org.mozilla.fenix.R
import org.mozilla.fenix.home.sessioncontrol.SwipeToDeleteCallback
import org.mozilla.fenix.library.bookmarks.viewholders.BookmarkNodeViewHolder
import org.mozilla.fenix.library.bookmarks.viewholders.BookmarkSeparatorViewHolder

class BookmarkTouchHelper(interactor: BookmarkViewInteractor) :
    ItemTouchHelper(BookmarkTouchCallback(interactor))

class BookmarkTouchCallback(
    private val interactor: BookmarkViewInteractor
) : ItemTouchHelper.SimpleCallback(0, ItemTouchHelper.LEFT or ItemTouchHelper.RIGHT) {

    override fun getSwipeDirs(
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder
    ): Int {
        // Swiping separators is currently not supported.
        if (viewHolder is BookmarkSeparatorViewHolder) {
            return 0
        }
        val item = (viewHolder as BookmarkNodeViewHolder).item
        return if (item?.inRoots() == true) {
            0
        } else {
            super.getSwipeDirs(recyclerView, viewHolder)
        }
    }

    /**
     * Delete the bookmark when swiped.
     */
    override fun onSwiped(viewHolder: RecyclerView.ViewHolder, direction: Int) {
        val item = (viewHolder as BookmarkNodeViewHolder).item
        item?.let {
            interactor.onDelete(setOf(it))
            // We need to notify the adapter of a change if we swipe a folder to prevent
            // visual bugs when cancelling deletion of a folder
            if (item.type == BookmarkNodeType.FOLDER) {
                viewHolder.bindingAdapter?.notifyItemChanged(viewHolder.bindingAdapterPosition)
            }
        }
    }

    override fun onChildDraw(
        c: Canvas,
        recyclerView: RecyclerView,
        viewHolder: RecyclerView.ViewHolder,
        dX: Float,
        dY: Float,
        actionState: Int,
        isCurrentlyActive: Boolean
    ) {
        super.onChildDraw(c, recyclerView, viewHolder, dX, dY, actionState, isCurrentlyActive)
        val icon = recyclerView.context.getDrawableWithTint(
            R.drawable.ic_delete,
            recyclerView.context.getColorFromAttr(R.attr.destructive)
        )!!
        val background = AppCompatResources.getDrawable(
            recyclerView.context,
            R.drawable.swipe_delete_background
        )!!
        val margin =
            SwipeToDeleteCallback.MARGIN.dpToPx(recyclerView.resources.displayMetrics)
        val cellHeight = viewHolder.itemView.bottom - viewHolder.itemView.top
        val iconTop = viewHolder.itemView.top + (cellHeight - icon.intrinsicHeight) / 2
        val iconBottom = iconTop + icon.intrinsicHeight

        when {
            dX > 0 -> { // Swiping to the right
                val backgroundBounds = Rect(
                    viewHolder.itemView.left, viewHolder.itemView.top,
                    (viewHolder.itemView.left + dX).toInt() + SwipeToDeleteCallback.BACKGROUND_CORNER_OFFSET,
                    viewHolder.itemView.bottom
                )
                val iconLeft = viewHolder.itemView.left + margin
                val iconRight = viewHolder.itemView.left + margin + icon.intrinsicWidth
                val iconBounds = Rect(iconLeft, iconTop, iconRight, iconBottom)

                setBounds(background, backgroundBounds, icon, iconBounds)
                draw(background, icon, c)
            }
            dX < 0 -> { // Swiping to the left
                val backgroundBounds = Rect(
                    (viewHolder.itemView.right + dX).toInt() - SwipeToDeleteCallback.BACKGROUND_CORNER_OFFSET,
                    viewHolder.itemView.top, viewHolder.itemView.right, viewHolder.itemView.bottom
                )
                val iconLeft = viewHolder.itemView.right - margin - icon.intrinsicWidth
                val iconRight = viewHolder.itemView.right - margin
                val iconBounds = Rect(iconLeft, iconTop, iconRight, iconBottom)

                setBounds(background, backgroundBounds, icon, iconBounds)
                draw(background, icon, c)
            }
            else -> { // View not swiped
                val bounds = Rect(0, 0, 0, 0)
                setBounds(background, bounds, icon, bounds)
            }
        }
    }

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

    override fun onSelectedChanged(viewHolder: RecyclerView.ViewHolder?, actionState: Int) {
        super.onSelectedChanged(viewHolder, actionState)
        if (actionState == ItemTouchHelper.ACTION_STATE_SWIPE) {
            interactor.onStartSwipingItem()
        } else {
            interactor.onStopSwipingItem()
        }
    }

    private fun setBounds(
        background: Drawable,
        backgroundBounds: Rect,
        icon: Drawable,
        iconBounds: Rect
    ) {
        background.bounds = backgroundBounds
        icon.bounds = iconBounds
    }

    private fun draw(background: Drawable, icon: Drawable, c: Canvas) {
        background.draw(c)
        icon.draw(c)
    }
}
