package ca.ksamad.encore.ui

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Add
import androidx.compose.material.icons.filled.PlayArrow
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SwipeToDismissBox
import androidx.compose.material3.SwipeToDismissBoxValue
import androidx.compose.material3.Text
import androidx.compose.material3.rememberSwipeToDismissBoxState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.dp

/** Fraction of a row's width a swipe must cross before the action fires (vs. the 56.dp default). */
private const val SWIPE_TRIGGER_FRACTION = 0.5f

/**
 * Wraps [content] in the app's shared "queue swipe" affordance: swipe right to [onAddToQueue]
 * (append), swipe left to [onPlayNext] (insert after the current track). Used for both album rows
 * and individual tracks so the gesture and its meaning stay identical wherever it appears.
 *
 * Both are one-shot actions, not deletions, so the row always springs back and stays in the list —
 * [content] should be opaque (e.g. a `ListItem`) so it hides the coloured reveal once settled.
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun QueueSwipeRow(
    onAddToQueue: () -> Unit,
    onPlayNext: () -> Unit,
    content: @Composable () -> Unit,
) {
    val state =
        rememberSwipeToDismissBoxState(
            // Require the swipe to cross half the row's width before it counts, rather
            // than the default fixed 56.dp — a small drag or flick was triggering the
            // queue/play-next action too easily.
            positionalThreshold = { totalDistance -> totalDistance * SWIPE_TRIGGER_FRACTION },
            confirmValueChange = { target ->
                when (target) {
                    SwipeToDismissBoxValue.StartToEnd -> {
                        onAddToQueue()
                    }

                    SwipeToDismissBoxValue.EndToStart -> {
                        onPlayNext()
                    }

                    SwipeToDismissBoxValue.Settled -> {}
                }
                false // Never settle to dismissed — snap back and keep the row.
            }
        )

    SwipeToDismissBox(
        state = state,
        backgroundContent = { SwipeActionBackground(state.dismissDirection) },
    ) {
        content()
    }
}

/**
 * The coloured reveal shown behind a swiping row: an "Add to queue" hint on the leading edge (swipe
 * right) and a "Play next" hint on the trailing edge (swipe left). Renders empty while the row is
 * settled.
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
private fun SwipeActionBackground(direction: SwipeToDismissBoxValue) {
    if (direction == SwipeToDismissBoxValue.Settled) {
        Box(Modifier.fillMaxSize())
        return
    }

    val queueing = direction == SwipeToDismissBoxValue.StartToEnd
    val container =
        if (queueing) {
            MaterialTheme.colorScheme.secondaryContainer
        } else {
            MaterialTheme.colorScheme.tertiaryContainer
        }
    val onContainer =
        if (queueing) {
            MaterialTheme.colorScheme.onSecondaryContainer
        } else {
            MaterialTheme.colorScheme.onTertiaryContainer
        }
    val icon = if (queueing) Icons.Filled.Add else Icons.Filled.PlayArrow
    val label = if (queueing) "Add to queue" else "Play next"

    Box(
        Modifier.fillMaxSize().background(container).padding(horizontal = 24.dp),
        contentAlignment = if (queueing) Alignment.CenterStart else Alignment.CenterEnd,
    ) {
        Row(verticalAlignment = Alignment.CenterVertically) {
            if (queueing) {
                Icon(icon, contentDescription = null, tint = onContainer)
                Spacer(Modifier.width(8.dp))
                Text(label, color = onContainer)
            } else {
                Text(label, color = onContainer)
                Spacer(Modifier.width(8.dp))
                Icon(icon, contentDescription = null, tint = onContainer)
            }
        }
    }
}
