package fn.compose.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBar
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import fn.compose.theme.FnColors
import fn.compose.theme.FnRadius
import fn.compose.theme.FnShadows
import fn.compose.theme.FnSpacing

/**
 * Vertical layout primitive. Wraps a [Column] with [Arrangement.spacedBy] using [gap].
 *
 * Equivalent to the web `<Stack>` component from `@fn_library` (Mantine Stack).
 * Use to stack items with consistent vertical spacing without inline padding.
 *
 * @param modifier Modifier applied to the outer [Column].
 * @param gap Space between children. Defaults to [FnSpacing.md] (16 dp).
 * @param content Composable children provided in [ColumnScope].
 */
@Composable
fun FnStack(
    modifier: Modifier = Modifier,
    gap: Dp = FnSpacing.md,
    content: @Composable ColumnScope.() -> Unit,
) {
    Column(
        modifier = modifier,
        verticalArrangement = Arrangement.spacedBy(gap),
        content = content,
    )
}

/**
 * Horizontal layout primitive. Wraps a [Row] with [Arrangement.spacedBy] using [gap]
 * and vertically centers children via [Alignment.CenterVertically].
 *
 * Equivalent to the web `<Group>` component from `@fn_library` (Mantine Group).
 * Use to place items side-by-side with consistent horizontal spacing.
 *
 * @param modifier Modifier applied to the outer [Row].
 * @param gap Space between children. Defaults to [FnSpacing.sm] (12 dp).
 * @param content Composable children provided in [RowScope].
 */
@Composable
fun FnGroup(
    modifier: Modifier = Modifier,
    gap: Dp = FnSpacing.sm,
    content: @Composable RowScope.() -> Unit,
) {
    Row(
        modifier = modifier,
        horizontalArrangement = Arrangement.spacedBy(gap),
        verticalAlignment = Alignment.CenterVertically,
        content = content,
    )
}

/**
 * Elevated container surface. Wraps a [Surface] with [FnColors.surface] background,
 * rounded corners ([FnRadius.md]) and a subtle tonal elevation ([FnShadows.xs]).
 *
 * Equivalent to the web `<Paper>` component from `@fn_library` (Mantine Paper).
 * Use when content needs a visual separation from the background without a heavy border.
 *
 * @param modifier Modifier applied to the [Surface].
 * @param content Composable children provided in [ColumnScope] with [FnSpacing.md] padding.
 */
@Composable
fun FnPaper(
    modifier: Modifier = Modifier,
    content: @Composable ColumnScope.() -> Unit,
) {
    Surface(
        modifier = modifier,
        color = FnColors.surface,
        shape = RoundedCornerShape(FnRadius.md),
        tonalElevation = FnShadows.xs,
    ) {
        Column(
            modifier = Modifier.padding(FnSpacing.md),
            content = content,
        )
    }
}

/**
 * Root application shell with a top app bar and a content slot that receives
 * the inner padding from [Scaffold].
 *
 * Equivalent to the web `<AppShell>` component from `@fn_library`. Place this
 * at the top of every screen composable so the system status bar and navigation
 * insets are handled consistently.
 *
 * The [TopAppBar] is annotated with [ExperimentalMaterial3Api] as required by
 * Compose Material 3 (BOM 2024.02.00). The opt-in is scoped to this function.
 *
 * @param title Text displayed in the top app bar.
 * @param modifier Modifier applied to the [Scaffold].
 * @param content Screen content. Receives [PaddingValues] from the scaffold and
 *   is responsible for applying them (e.g. via [Modifier.padding]).
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FnAppShell(
    title: String,
    modifier: Modifier = Modifier,
    content: @Composable (PaddingValues) -> Unit,
) {
    Scaffold(
        modifier = modifier,
        topBar = {
            TopAppBar(
                title = { Text(text = title) },
            )
        },
        content = content,
    )
}
