package dev.ulfrx.recipe.ui.screens.shell.search

import androidx.compose.animation.AnimatedVisibility
import androidx.compose.animation.EnterTransition
import androidx.compose.animation.core.FastOutSlowInEasing
import androidx.compose.animation.core.tween
import androidx.compose.animation.expandHorizontally
import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkHorizontally
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalFocusManager
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import com.composables.icons.lucide.Lucide
import com.composables.icons.lucide.X
import dev.ulfrx.recipe.navigation.DockDestination
import dev.ulfrx.recipe.ui.components.glass.CircleGlassButton
import dev.ulfrx.recipe.ui.screens.shell.dock.DockBar
import dev.ulfrx.recipe.ui.theme.RecipeTheme
import org.jetbrains.compose.resources.stringResource
import recipe.composeapp.generated.resources.Res
import recipe.composeapp.generated.resources.search_dismiss_keyboard_a11y

/**
 * Bottom chrome rendered while shell-wide search is open (states B and C from
 * [SearchState]).
 *
 * Layout decided from [SearchState.isFocused]:
 *  - **B (`isFocused=false`)** — `[ collapsed dock icon ] [ search pill ]`.
 *    Tapping the collapsed dock icon closes search and returns to [activeTab].
 *  - **C (`isFocused=true`)** — `[ search pill (full width) ] [ X button ]`.
 *    The collapsed dock icon disappears (Apple Music pattern: the left affordance
 *    yields to the search context). Tapping X clears the query and unfocuses
 *    back to State B.
 *
 * Geometry mirrors the existing chrome: 45dp height, capsule shapes,
 * [RecipeTheme.spacing.sm] gap between cells.
 *
 * Focus wiring is bi-directional: when [SearchPill]'s `BasicTextField` reports
 * focus changes, [onFocusGained] / [onFocusLost] propagate them into the shell
 * VM. When the VM commands `isFocused=false` (e.g. via X), a [LaunchedEffect]
 * here drives `focusManager.clearFocus()` to flush the platform focus.
 */
@Composable
fun SearchPillRow(
    query: String,
    isFocused: Boolean,
    placeholder: String,
    activeTab: DockDestination,
    onQueryChange: (String) -> Unit,
    onClose: () -> Unit,
    onFocusGained: () -> Unit,
    onFocusLost: () -> Unit,
) {
    val focusManager = LocalFocusManager.current
    // Search pill / collapsed dock icon / X button — all share this height.
    // AppShell vertically centres the SearchPillRow within the dock's 63dp
    // band so the pill sits in the middle of the tab-bar position rather than
    // nudged toward the top.
    val pillHeight = 48.dp

    // VM-commanded unfocus → flush platform focus from BasicTextField.
    LaunchedEffect(isFocused) {
        if (!isFocused) focusManager.clearFocus()
    }

    // Shared spec for the B↔C side-button transitions. expand/shrink animate
    // the slot width from 0 ↔ natural, so the pill (weight 1f) smoothly takes
    // / yields space rather than snapping when the dock icon / X swap in/out.
    // Same 200 ms FastOutSlowInEasing as the chrome's horizontal-padding
    // animation in AppShell, so the two move in lockstep.
    val sideButtonEnter =
        expandHorizontally(tween(durationMillis = 200, easing = FastOutSlowInEasing)) +
            fadeIn(tween(durationMillis = 200, easing = FastOutSlowInEasing))
    val sideButtonExit =
        shrinkHorizontally(tween(durationMillis = 200, easing = FastOutSlowInEasing)) +
            fadeOut(tween(durationMillis = 200, easing = FastOutSlowInEasing))

    Row(
        modifier = Modifier.fillMaxWidth(),
        horizontalArrangement = Arrangement.spacedBy(RecipeTheme.spacing.sm),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        AnimatedVisibility(
            visible = !isFocused,
            // C → B: the collapsed dock icon should already be present at the
            // bottom — feels jarring if it visibly slides/fades in while the
            // keyboard is still dismissing. Only its exit (B → C) needs to
            // smoothly clear the slot for the search pill to grow into.
            enter = EnterTransition.None,
            exit = sideButtonExit,
        ) {
            DockBar(
                destinations = DockDestination.entries,
                active = activeTab,
                collapsed = true,
                // Collapsed dock only emits a re-select of the active tab,
                // which here means "close the search overlay".
                onTabSelect = { onClose() },
                height = pillHeight,
            )
        }
        SearchPill(
            query = query,
            onQueryChange = onQueryChange,
            onFocusChanged = { focused ->
                if (focused) onFocusGained() else onFocusLost()
            },
            placeholder = placeholder,
            modifier = Modifier.weight(1f),
            height = pillHeight,
        )
        AnimatedVisibility(
            visible = isFocused,
            enter = sideButtonEnter,
            exit = sideButtonExit,
        ) {
            DismissSearchKeyboardButton(
                onClick = onFocusLost,
                size = pillHeight,
            )
        }
    }
}

/**
 * Circular Liquid-glass X button. Visible only in State C — tapping it
 * unfocuses the search field and clears the query (returns to State B).
 * Press feedback (scale + tint) is owned by [CircleGlassButton].
 */
@Composable
private fun DismissSearchKeyboardButton(
    onClick: () -> Unit,
    size: Dp,
) {
    CircleGlassButton(
        onClick = onClick,
        icon = Lucide.X,
        contentDescription = stringResource(Res.string.search_dismiss_keyboard_a11y),
        size = size,
    )
}
