package fn.compose.ui

import androidx.compose.animation.core.LinearEasing
import androidx.compose.animation.core.RepeatMode
import androidx.compose.animation.core.animateFloat
import androidx.compose.animation.core.infiniteRepeatable
import androidx.compose.animation.core.rememberInfiniteTransition
import androidx.compose.animation.core.tween
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ScrollableTabRow
import androidx.compose.material3.Tab
import androidx.compose.material3.TabRow
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import fn.compose.theme.FnColors
import fn.compose.theme.FnRadius
import fn.compose.theme.FnSpacing
import fn.compose.theme.FnTypography

// ---------------------------------------------------------------------------
// FnTabs
// ---------------------------------------------------------------------------

/**
 * Tab bar backed by [TabRow] or [ScrollableTabRow] depending on [scrollable].
 *
 * Each item in [tabs] becomes a [Tab] whose selected state is determined by
 * comparing its index with [selectedIndex]. Selecting a tab triggers
 * [onTabSelected] with the tapped index.
 */
@Composable
fun FnTabs(
    tabs: List<String>,
    selectedIndex: Int,
    onTabSelected: (Int) -> Unit,
    modifier: Modifier = Modifier,
    scrollable: Boolean = false,
) {
    val tabContent: @Composable () -> Unit = {
        tabs.forEachIndexed { index, label ->
            Tab(
                selected = index == selectedIndex,
                onClick = { onTabSelected(index) },
                text = { Text(label) },
            )
        }
    }

    if (scrollable) {
        ScrollableTabRow(
            selectedTabIndex = selectedIndex,
            modifier = modifier,
        ) { tabContent() }
    } else {
        TabRow(
            selectedTabIndex = selectedIndex,
            modifier = modifier,
        ) { tabContent() }
    }
}

// ---------------------------------------------------------------------------
// FnAlert
// ---------------------------------------------------------------------------

/** Semantic intent of an [FnAlert]. Maps to a status color from [FnColors]. */
enum class FnAlertVariant { Info, Success, Warning, Error }

/**
 * Inline alert banner.
 *
 * The background is the variant's status color at 15 % opacity; the border is
 * the same color at full opacity (1 dp). When [title] is supplied it is
 * rendered in bold above [text].
 */
@Composable
fun FnAlert(
    text: String,
    modifier: Modifier = Modifier,
    title: String? = null,
    variant: FnAlertVariant = FnAlertVariant.Info,
) {
    val colorBase: Color = when (variant) {
        FnAlertVariant.Info    -> FnColors.info
        FnAlertVariant.Success -> FnColors.success
        FnAlertVariant.Warning -> FnColors.warning
        FnAlertVariant.Error   -> FnColors.error
    }
    val shape = RoundedCornerShape(FnRadius.sm)
    val onSurface = MaterialTheme.colorScheme.onSurface

    Box(
        modifier = modifier
            .fillMaxWidth()
            .clip(shape)
            .background(colorBase.copy(alpha = 0.15f))
            .border(width = 1.dp, color = colorBase, shape = shape)
            .padding(FnSpacing.md),
    ) {
        Column(verticalArrangement = Arrangement.spacedBy(4.dp)) {
            if (title != null) {
                Text(
                    text = title,
                    color = colorBase,
                    fontWeight = FontWeight.Bold,
                    fontSize = FnTypography.sm,
                )
            }
            Text(
                text = text,
                color = onSurface,
                fontSize = FnTypography.sm,
            )
        }
    }
}

// ---------------------------------------------------------------------------
// FnLoader
// ---------------------------------------------------------------------------

/** Visual size of an [FnLoader] spinner. */
enum class FnLoaderSize { Sm, Md, Lg }

/**
 * Indeterminate circular progress indicator using [FnColors.primary].
 *
 * [size] maps to 16 dp (Sm), 32 dp (Md), or 56 dp (Lg). The stroke width
 * scales proportionally (2 / 3 / 5 dp).
 */
@Composable
fun FnLoader(
    modifier: Modifier = Modifier,
    size: FnLoaderSize = FnLoaderSize.Md,
) {
    val (sizeDp, strokeDp) = when (size) {
        FnLoaderSize.Sm -> 16.dp to 2.dp
        FnLoaderSize.Md -> 32.dp to 3.dp
        FnLoaderSize.Lg -> 56.dp to 5.dp
    }

    CircularProgressIndicator(
        modifier = modifier.size(sizeDp),
        color = FnColors.primary,
        strokeWidth = strokeDp,
    )
}

// ---------------------------------------------------------------------------
// FnSkeleton
// ---------------------------------------------------------------------------

/**
 * Shimmer placeholder rectangle.
 *
 * Fills the available width to [height] dp with a rounded shape and an
 * animated alpha oscillating between [FnColors.surfaceHover] and
 * [FnColors.surfaceActive], simulating a loading shimmer without external
 * dependencies.
 */
@Composable
fun FnSkeleton(
    modifier: Modifier = Modifier,
    height: Dp = 16.dp,
) {
    val infiniteTransition = rememberInfiniteTransition(label = "skeleton_shimmer")
    val alpha by infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            animation = tween(durationMillis = 800, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse,
        ),
        label = "skeleton_alpha",
    )

    // Interpolate between surfaceHover and surfaceActive using the animated alpha.
    val shimmerColor = androidx.compose.ui.graphics.lerp(
        FnColors.surfaceHover,
        FnColors.surfaceActive,
        alpha,
    )

    Box(
        modifier = modifier
            .fillMaxWidth()
            .height(height)
            .clip(RoundedCornerShape(FnRadius.sm))
            .background(shimmerColor),
    )
}

// ---------------------------------------------------------------------------
// FnEmptyState
// ---------------------------------------------------------------------------

/**
 * Centred empty-state panel with optional icon, title, description, and
 * action slot.
 *
 * Layout (top to bottom, horizontally centred):
 *  1. [icon] rendered as large emoji/text (40 sp) — only if non-null.
 *  2. [title] in bold body size.
 *  3. [description] in [FnColors.textMuted].
 *  4. [action] composable slot — only if non-null.
 *
 * Padding is [FnSpacing.lg] on all sides; vertical gaps use [FnSpacing.sm].
 */
@Composable
fun FnEmptyState(
    title: String,
    description: String,
    modifier: Modifier = Modifier,
    icon: String? = null,
    action: (@Composable () -> Unit)? = null,
) {
    Column(
        modifier = modifier.padding(FnSpacing.lg),
        horizontalAlignment = Alignment.CenterHorizontally,
        verticalArrangement = Arrangement.spacedBy(FnSpacing.sm),
    ) {
        if (icon != null) {
            Text(
                text = icon,
                fontSize = 40.sp,
            )
        }
        Text(
            text = title,
            fontWeight = FontWeight.Bold,
            fontSize = FnTypography.md,
        )
        Text(
            text = description,
            color = FnColors.textMuted,
            fontSize = FnTypography.sm,
        )
        action?.invoke()
    }
}
