package theorycrafter.ui.widgets

import androidx.compose.foundation.background
import androidx.compose.foundation.layout.*
import androidx.compose.material.*
import androidx.compose.runtime.*
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.DpOffset
import androidx.compose.ui.unit.LayoutDirection
import androidx.compose.ui.unit.dp
import compose.input.KeyShortcut
import compose.utils.HSpacer
import compose.widgets.IconButton
import compose.widgets.SingleLineText
import theorycrafter.ui.Icons
import theorycrafter.ui.TheorycrafterTheme


/**
 * A context menu.
 */
@Composable
fun ContextMenu(
    state: DropdownMenuState,
    onDismissRequest: () -> Unit = { state.status = DropdownMenuState.Status.Closed },
    modifier: Modifier = Modifier,
    content: @Composable ColumnScope.() -> Unit
) {
    DropdownMenu(
        state = state,
        onDismissRequest = onDismissRequest,
        modifier = modifier,
        content = content
    )
}


/**
 * A button that displays an icon and opens a [DropdownMenu] with the given list of menu items.
 */
@Composable
fun IconMenuButton(
    modifier: Modifier = Modifier,
    icon: ImageVector = Icons.MenuImageVector,
    iconPadding: PaddingValues = PaddingValues(4.dp),
    contentDescription: String,
    menuContent: @Composable ColumnScope.(onCloseMenu: () -> Unit) -> Unit,
) {
    MenuButton(
        modifier = modifier,
        content = { onClick ->
            IconButton(onClick = onClick) {
                Icon(
                    imageVector = icon,
                    contentDescription = contentDescription,
                    modifier = Modifier.padding(iconPadding)
                )
            }
        },
        menuContent = menuContent
    )
}


/**
 * A button that opens a [DropdownMenu] with the given list of menu items.
 */
@Composable
fun MenuButton(
    modifier: Modifier = Modifier,
    offset: DpOffset = DpOffset(0.dp, 0.dp),
    content: @Composable (onClick: () -> Unit) -> Unit,
    menuContent: @Composable ColumnScope.(onCloseMenu: () -> Unit) -> Unit,
) {
    var showMenu: Boolean by remember { mutableStateOf(false) }

    Box(modifier = modifier) {
        content {
            showMenu = true
        }

        DropdownMenu(
            expanded = showMenu,
            offset = offset,
            onDismissRequest = {
                showMenu = false
            },
            content = {
                menuContent { showMenu = false }
            }
        )
    }
}


/**
 * A [DropdownMenuItem] that displays an icon, some text, and a key shortcut that triggers the action.
 * Triggers the action when clicked.
 */
@Composable
fun MenuItem(


    /**
     * The text to display.
     */
    text: String,


    /**
     * Whether the menu item is enabled.
     */
    enabled: Boolean = true,


    /**
     * The icon.
     */
    icon: (@Composable () -> Unit)? = null,


    /**
     * The key shortcut to display, which also triggers the action.
     *
     * Note that this is just for display; the menu item doesn't actually trigger the action when the key shortcut is
     * pressed.
     */
    displayedKeyShortcut: KeyShortcut? = null,


    /**
     * Whether to reserve space for a keyboard shortcut even if it's `null`.
     */
    reserveSpaceForKeyShortcut: Boolean = false,


    /**
     * The key shortcut descriptor width.
     */
    keyShortcutDescriptorWidth: Dp = TheorycrafterTheme.sizes.menuItemKeyShortcutWidthSmall,


    /**
     * Closes the menu item.
     */
    onCloseMenu: () -> Unit,


    /**
     * The function to call when the menu item is clicked.
     */
     action: () -> Unit


) {
    // Workaround for https://issuetracker.google.com/issues/309849981
    val iconContent = remember {
        if (icon != null)
            movableContentOf(icon)
        else
            null
    }

    // Workaround for https://issuetracker.google.com/issues/309849981
    val content = remember {
        movableContentWithReceiverOf<RowScope> {
            if (iconContent != null) {
                Box(
                    modifier = Modifier
                        .padding(end = TheorycrafterTheme.spacing.xsmall)
                        .size(TheorycrafterTheme.sizes.menuItemIconSize)
                ) {
                    iconContent()
                }
            }

            SingleLineText(
                text = text,
                style = TheorycrafterTheme.textStyles.menuItem
            )
            if ((displayedKeyShortcut != null) || reserveSpaceForKeyShortcut) {
                Spacer(
                    modifier = Modifier
                        .weight(1f)
                        .widthIn(min = TheorycrafterTheme.spacing.larger)
                )
                if (displayedKeyShortcut != null) {
                    SingleLineText(
                        modifier = Modifier.width(keyShortcutDescriptorWidth),
                        text = displayedKeyShortcut.displayString(),
                        textAlign = TextAlign.End,
                        color = TheorycrafterTheme.colors.menuItemSecondary(),
                        style = TheorycrafterTheme.textStyles.menuItem
                    )
                }
                else {
                    HSpacer(keyShortcutDescriptorWidth)
                }
            }
        }
    }

    // Workaround for https://issuetracker.google.com/issues/309849981
    val firstEnabled = remember { enabled }

    compose.widgets.DropdownMenuItem(
        onClick = {
            action()
            onCloseMenu()
        },
        enabled = firstEnabled
    ) {
        content()
    }
}


/**
 * A menu item separator.
 */
@Composable
fun MenuSeparator() {
    val horizontalPadding =
        MenuDefaults.DropdownMenuItemContentPadding.calculateLeftPadding(LayoutDirection.Ltr) * 0.75f
    Box(
        Modifier
            .fillMaxWidth()
            .padding(horizontal = horizontalPadding)
            .padding(vertical = TheorycrafterTheme.spacing.xxsmall)
            .height(1.dp)
            .background(TheorycrafterTheme.colors.menuItemSeparator())
    )
}


/**
 * A menu item heading.
 */
@Composable
fun MenuItemHeading(text: String, extraTopPadding: Boolean = true) {
    Text(
        text = text,
        style = TheorycrafterTheme.textStyles.menuItemHeading(),
        modifier = Modifier
            .padding(MenuDefaults.DropdownMenuItemContentPadding)  // This only gives horizontal padding
            .padding(
                top = if (extraTopPadding) TheorycrafterTheme.spacing.larger else TheorycrafterTheme.spacing.xsmall,
                bottom = TheorycrafterTheme.spacing.xxxsmall
            )
    )
}


/**
 * An empty icon that can be used as the `icon` argument to [MenuItem] in order to take space and align the text with
 * other items in the same menu.
 */
val EmptyIcon = @Composable fun() { }