package fn.compose.ui

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Checkbox
import androidx.compose.material3.DropdownMenuItem
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.ExposedDropdownMenuBox
import androidx.compose.material3.ExposedDropdownMenuDefaults
import androidx.compose.material3.OutlinedButton
import androidx.compose.material3.OutlinedTextField
import androidx.compose.material3.Switch
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.TextDecoration
import androidx.compose.ui.unit.dp
import fn.compose.theme.FnColors
import fn.compose.theme.FnRadius
import fn.compose.theme.FnSpacing

// ---------------------------------------------------------------------------
// Button
// ---------------------------------------------------------------------------

/** Variants for [FnButton]. Maps to Material3 button styles + custom colors. */
enum class FnButtonVariant {
    Filled,
    Outlined,
    Secondary,
    Ghost,
    Destructive,
    Link,
}

private val buttonShape = RoundedCornerShape(FnRadius.sm)

/**
 * Design-system button with six visual variants. Stateless — the caller
 * drives [onClick].
 *
 * - Filled: primary container color.
 * - Outlined: border only, no fill.
 * - Secondary: filled with [FnColors.surfaceActive].
 * - Ghost: text-only, no chrome.
 * - Destructive: filled with [FnColors.error].
 * - Link: text-only with [FnColors.primary] color and underline decoration.
 */
@Composable
fun FnButton(
    text: String,
    onClick: () -> Unit,
    modifier: Modifier = Modifier,
    variant: FnButtonVariant = FnButtonVariant.Filled,
) {
    val shape = buttonShape
    when (variant) {
        FnButtonVariant.Filled -> Button(
            onClick = onClick,
            modifier = modifier,
            shape = shape,
        ) {
            Text(text)
        }

        FnButtonVariant.Outlined -> OutlinedButton(
            onClick = onClick,
            modifier = modifier,
            shape = shape,
        ) {
            Text(text)
        }

        FnButtonVariant.Secondary -> Button(
            onClick = onClick,
            modifier = modifier,
            shape = shape,
            colors = ButtonDefaults.buttonColors(
                containerColor = FnColors.surfaceActive,
                contentColor = FnColors.text,
            ),
        ) {
            Text(text)
        }

        FnButtonVariant.Ghost -> TextButton(
            onClick = onClick,
            modifier = modifier,
            shape = shape,
        ) {
            Text(text)
        }

        FnButtonVariant.Destructive -> Button(
            onClick = onClick,
            modifier = modifier,
            shape = shape,
            colors = ButtonDefaults.buttonColors(
                containerColor = FnColors.error,
                contentColor = FnColors.white,
            ),
        ) {
            Text(text)
        }

        FnButtonVariant.Link -> TextButton(
            onClick = onClick,
            modifier = modifier,
            shape = shape,
        ) {
            Text(
                text = text,
                color = FnColors.primary,
                textDecoration = TextDecoration.Underline,
            )
        }
    }
}

// ---------------------------------------------------------------------------
// Text input
// ---------------------------------------------------------------------------

/**
 * Single-line text field with optional label, placeholder and inline error.
 * Stateless — the caller owns [value] / [onValueChange].
 *
 * When [error] is non-null, the field enters error state and the supporting
 * text slot shows the error message in [FnColors.error].
 */
@Composable
fun FnTextInput(
    value: String,
    onValueChange: (String) -> Unit,
    modifier: Modifier = Modifier,
    label: String? = null,
    placeholder: String? = null,
    error: String? = null,
) {
    OutlinedTextField(
        value = value,
        onValueChange = onValueChange,
        modifier = modifier,
        label = label?.let { { Text(it) } },
        placeholder = placeholder?.let { { Text(it) } },
        isError = error != null,
        singleLine = true,
        supportingText = error?.let {
            {
                Text(
                    text = it,
                    color = FnColors.error,
                )
            }
        },
    )
}

// ---------------------------------------------------------------------------
// Select (dropdown)
// ---------------------------------------------------------------------------

/**
 * Exposed dropdown menu that lets the caller pick one item from [options].
 * Stateless — the caller drives [selected] / [onSelected].
 *
 * Annotated with [ExperimentalMaterial3Api] because [ExposedDropdownMenuBox]
 * is part of the experimental Material3 API surface in BOM 2024.02.00.
 */
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun FnSelect(
    options: List<String>,
    selected: String?,
    onSelected: (String) -> Unit,
    modifier: Modifier = Modifier,
    label: String? = null,
) {
    var expanded by remember { mutableStateOf(false) }

    ExposedDropdownMenuBox(
        expanded = expanded,
        onExpandedChange = { expanded = it },
        modifier = modifier,
    ) {
        OutlinedTextField(
            value = selected ?: "",
            onValueChange = {},
            readOnly = true,
            label = label?.let { { Text(it) } },
            trailingIcon = { ExposedDropdownMenuDefaults.TrailingIcon(expanded = expanded) },
            modifier = Modifier
                .menuAnchor()
                .fillMaxWidth(),
        )
        ExposedDropdownMenu(
            expanded = expanded,
            onDismissRequest = { expanded = false },
        ) {
            options.forEach { option ->
                DropdownMenuItem(
                    text = { Text(option) },
                    onClick = {
                        onSelected(option)
                        expanded = false
                    },
                )
            }
        }
    }
}

// ---------------------------------------------------------------------------
// Switch
// ---------------------------------------------------------------------------

/**
 * Labeled toggle. The [label] is rendered to the right of the [Switch] when
 * non-null. Stateless — the caller owns [checked] / [onCheckedChange].
 */
@Composable
fun FnSwitch(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    label: String? = null,
) {
    Row(
        modifier = modifier,
        horizontalArrangement = Arrangement.spacedBy(FnSpacing.sm),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Switch(
            checked = checked,
            onCheckedChange = onCheckedChange,
        )
        if (label != null) {
            Text(text = label)
        }
    }
}

// ---------------------------------------------------------------------------
// Checkbox
// ---------------------------------------------------------------------------

/**
 * Labeled checkbox. The [label] is rendered to the right of the [Checkbox]
 * when non-null. Stateless — the caller owns [checked] / [onCheckedChange].
 */
@Composable
fun FnCheckbox(
    checked: Boolean,
    onCheckedChange: (Boolean) -> Unit,
    modifier: Modifier = Modifier,
    label: String? = null,
) {
    Row(
        modifier = modifier,
        horizontalArrangement = Arrangement.spacedBy(FnSpacing.sm),
        verticalAlignment = Alignment.CenterVertically,
    ) {
        Checkbox(
            checked = checked,
            onCheckedChange = onCheckedChange,
        )
        if (label != null) {
            Text(text = label)
        }
    }
}

// ---------------------------------------------------------------------------
// Dialog
// ---------------------------------------------------------------------------

/**
 * Modal confirmation dialog.
 *
 * Rendered only when [open] is true. Provides "Confirmar" (calls [onConfirm])
 * and "Cancelar" (calls [onDismiss]) text buttons. The caller is responsible
 * for updating the [open] flag in response to those callbacks.
 */
@Composable
fun FnDialog(
    open: Boolean,
    onDismiss: () -> Unit,
    title: String,
    description: String,
    onConfirm: () -> Unit,
    modifier: Modifier = Modifier,
) {
    if (open) {
        AlertDialog(
            onDismissRequest = onDismiss,
            title = { Text(title) },
            text = { Text(description) },
            confirmButton = {
                TextButton(onClick = onConfirm) { Text("Confirmar") }
            },
            dismissButton = {
                TextButton(onClick = onDismiss) { Text("Cancelar") }
            },
            modifier = modifier,
        )
    }
}
