package theorycrafter.ui.widgets

import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.interaction.collectIsFocusedAsState
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.onClick
import androidx.compose.material.LocalTextStyle
import androidx.compose.material.Text
import androidx.compose.runtime.*
import androidx.compose.ui.ExperimentalComposeUiApi
import androidx.compose.ui.Modifier
import androidx.compose.ui.focus.FocusRequester
import androidx.compose.ui.focus.focusRequester
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.input.pointer.*
import androidx.compose.ui.text.input.TextFieldValue
import compose.input.KeyShortcut
import compose.input.onKeyShortcut
import compose.utils.LocalKeyShortcutsManager
import compose.widgets.SingleLineText
import theorycrafter.ui.Icons
import theorycrafter.ui.OutlinedTextField
import theorycrafter.ui.TheorycrafterTheme
import theorycrafter.utils.withAllTextSelected


/**
 * A text field for searching/filtering.
 */
@OptIn(ExperimentalFoundationApi::class, ExperimentalComposeUiApi::class)
@Composable
fun SearchField(
    modifier: Modifier,
    searchText: String? = null,
    placeholderText: String,
    focusKeyShortcut: KeyShortcut? = null,
    onSearched: (String) -> Unit
) {
    var textFieldValue by remember { mutableStateOf(TextFieldValue()) }.also {
        // Allow clearing the text from outside
        if ((searchText != null) && (it.value.text != searchText))
            it.value = TextFieldValue(searchText)
    }

    val focusRequester = remember { FocusRequester() }
    val interactionSource = remember { MutableInteractionSource() }

    fun clearSearch() {
        if (textFieldValue.text.isNotEmpty()) {
            textFieldValue = TextFieldValue()
            onSearched("")
        }
    }

    val isFocused by interactionSource.collectIsFocusedAsState()

    // Selects the text on mouse-release
    var selectAllOnRelease by remember { mutableStateOf(false) }
    val selectAllOnReleaseModifier = Modifier
        .onPointerEvent(PointerEventType.Press, pass = PointerEventPass.Initial) {
            selectAllOnRelease = !isFocused
        }
        .onPointerEvent(PointerEventType.Move) {
            // This should take mouse slop into account, but we can't easily because onDrag and onClick are consumed
            // inside the textfield.
            selectAllOnRelease = false
        }
        .onPointerEvent(PointerEventType.Release, pass = PointerEventPass.Final) {
            if (selectAllOnRelease) {
                textFieldValue = textFieldValue.withAllTextSelected()
            }
        }

    TheorycrafterTheme.OutlinedTextField(
        value = textFieldValue,
        onValueChange = {
            val textChanged = it.text != textFieldValue.text
            textFieldValue = it
            if (textChanged)
                onSearched(it.text)
        },
        modifier = modifier
            .focusRequester(focusRequester)
            .onKeyShortcut(Key.Escape) {
                if (textFieldValue.text.isNotEmpty())
                    clearSearch()
                else
                    consumeEvent = false
            }
            .then(selectAllOnReleaseModifier),
        leadingIcon = { Icons.Search(contentDescription = "Search") },
        interactionSource = interactionSource,
        trailingIcon = {
            if (textFieldValue.text.isNotEmpty()) {
                Icons.Cancel(
                    modifier = Modifier
                        .onClick {
                            clearSearch()
                            focusRequester.requestFocus()
                        }
                        .pointerHoverIcon(PointerIcon.Default)
                )
            } else if (!isFocused && (focusKeyShortcut != null)) {
                Text(
                    text = focusKeyShortcut.toString(),
                    style = LocalTextStyle.current.let {
                        it.copy(
                            fontSize = it.fontSize * 0.8
                        )
                    },
                    modifier = Modifier
                        .padding(end = TheorycrafterTheme.spacing.xlarge)
                )
            }
        },
        placeholder = { SingleLineText(placeholderText) },
        singleLine = true,
        colors = TheorycrafterTheme.colors.textFieldColors(
            unfocusedIndicatorColor = Color.Transparent,
        )
    )

    // This doesn't work due to https://youtrack.jetbrains.com/issue/CMP-1613/Unable-to-select-in-TextField-on-focus,
    // and maybe in general isn't such a good idea because we don't want to select all on mouse-down; we want it on
    // tap/click, to avoid interfering with the user to selecting text himself.
//    interactionSource.onGainedFocus {
//        textFieldValue = textFieldValue.withAllTextSelected()
//    }

    if (focusKeyShortcut != null) {
        LocalKeyShortcutsManager.current.register(
            shortcut = focusKeyShortcut,
            action = {
                focusRequester.requestFocus()
                textFieldValue = textFieldValue.withAllTextSelected()
            }
        )
    }
}