@file:Suppress("TestFunctionName")

package compose.widgets

import androidx.compose.foundation.layout.height
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.input.key.Key
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.test.*
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue


/**
 * Tests [SimpleGrid].
 */
@OptIn(ExperimentalTestApi::class)
class SimpleGridTest {


    /**
     * Tests drag-and-drop to reorder.
     */
    @Test
    fun testBasicDragToReorder() = runComposeUiTest {
        var draggedRow: Int? = null
        var dropRow: Int? = null

        setContent {
            TestSimpleGrid(
                rows = 3,
                columnWidths = listOf(100.dp, 100.dp),
                rowHeight = 30.dp,
                rowModifier = {
                    Modifier.dragRowToReorder(
                        draggableContent = { Text("Dragging") },
                        canMoveToRow = { true },
                        onDrop = { draggedRowIndex, dropRowIndex ->
                            draggedRow = draggedRowIndex
                            dropRow = dropRowIndex
                        }
                    )
                }
            )
        }

        // Test dragging the 1st row to after the 2nd
        onNodeWithTag("row-0").performMouseInput {
            dragAndDrop(
                start = Offset(10f, 10f),
                end = Offset(10f, 40f),
            )
        }
        assertEquals(0, draggedRow)
        assertEquals(1, dropRow)

        // Test dragging the 3rd row to the start of the list
        onNodeWithTag("row-2").performMouseInput {
            dragAndDrop(
                start = Offset(10f, 10f),
                end = Offset(10f, -70f),
            )
        }
        assertEquals(2, draggedRow)
        assertEquals(0, dropRow)
    }


    /**
     * Tests that pressing ESCAPE cancels the dragging.
     */
    @Test
    fun testEscapeCancelsDragging() = runComposeUiTest {
        var onDroppedCalled = false
        var onDragCancelledCalled = false
        setContent {
            TestSimpleGrid(
                rows = 3,
                columnWidths = listOf(100.dp, 100.dp),
                rowHeight = 30.dp,
                rowModifier = {
                    Modifier.dragRowToReorder(
                        draggableContent = { Text("Dragging") },
                        canMoveToRow = { true },
                        onDrop = { _, _ -> onDroppedCalled = true },
                        onDragCancelled = { onDragCancelledCalled = true}
                    )
                }
            )
        }

        onNodeWithTag("row-0").let {
            it.performMouseInput {
                updatePointerTo(Offset(10f, 10f))
                press(MouseButton.Primary)
                animateTo(Offset(10f, 40f), 300L)
            }
            it.performKeyInput {
                pressKey(Key.Escape)
            }
        }
        assertFalse(onDroppedCalled)
        assertTrue(onDragCancelledCalled)
    }


    /**
     * A test [SimpleGrid].
     */
    @Composable
    private fun TestSimpleGrid(
        rows: Int,
        columnWidths: List<Dp>,
        rowHeight: Dp,
        rowModifier: GridScope.(Int) -> Modifier = { Modifier },
    ) {
        SimpleGrid(
            columnWidths = columnWidths,
            modifier = Modifier
                .testTag("grid")
        ) {
            for (rowIndex in 0..rows) {
                row(
                    rowIndex = rowIndex,
                    modifier = Modifier
                        .height(rowHeight)
                        .testTag("row-$rowIndex")
                        .then(rowModifier(this, rowIndex))
                ) {
                    for (cellIndex in 0..columnWidths.lastIndex) {
                        cell(cellIndex, modifier = Modifier.testTag("cell-$cellIndex")) {
                            Text("$rowIndex-$cellIndex")
                        }
                    }
                }
            }
        }
    }


}


