package theorycrafter.ui.fiteditor

import androidx.compose.ui.test.ExperimentalTestApi
import androidx.compose.ui.test.assertAny
import androidx.compose.ui.test.hasText
import androidx.compose.ui.test.runDesktopComposeUiTest
import eve.data.DroneType
import theorycrafter.*
import theorycrafter.TheorycrafterContext.fits
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotEquals


/**
 * Tests the drone carousel in the fit editor.
 */
@OptIn(ExperimentalTestApi::class)
class DroneCarouselTest: TheorycrafterTest() {


    /**
     * The "Hornet EC-300" drone type.
     */
    private val hornetEc300: DroneType by lazy {
        TheorycrafterContext.eveData.droneType("Hornet EC-300")
    }


    /**
     * Test that the drone carousel preserves the number of drones of each type as you walk it right and left.
     */
    @Test
    fun droneAmountIsPreserved() = runDesktopComposeUiTest {
        val fit = newFit(
            shipName = "Scorpion Navy Issue",
            isValid = { it.drones.bandwidth.total < 100.0 }
        )

        fits.modifyAndSave {
            fit.addDroneGroup(hornetEc300, 4)
        }

        setApplicationContent {
            FitEditor(fit)
        }

        onNode(Nodes.FitEditor.droneRow(0)).let {
            it.scrollToAndClick()
            assertEquals(4, fit.firstDroneGroupSize(), "Amount of Hornet EC-300's is incorrect")
            it.press(FitEditorSlotKeys.CarouselNext)  // Vespa EC-600
            it.press(FitEditorSlotKeys.CarouselNext)  // Wasp EC-900
            assertNotEquals(4, fit.firstDroneGroupSize(), "Unexpected amount of Wasp EC-900's")
            it.press(FitEditorSlotKeys.CarouselPrev)  // Vespa EC-600
            it.press(FitEditorSlotKeys.CarouselPrev)  // Hornet EC-300
            assertEquals(4, fit.firstDroneGroupSize(), "Amount of Hornet EC-300's was not preserved")
        }
    }


    /**
     * Test that the drone carousel does not exceed the maximum allowed number of drones in a group.
     */
    @Test
    fun droneAmountDoesNotExceedMaximum() = runDesktopComposeUiTest {
        val fit = newFit(
            shipName = "Algos",
            isValid = { it.drones.bandwidth.total == 35.0 }
        )

        fits.modifyAndSave {
            fit.addDroneGroup(hornetEc300, 5)
        }

        setApplicationContent {
            FitEditor(fit)
        }

        onNode(Nodes.FitEditor.droneRow(0)).let {
            it.scrollToAndClick()
            assertEquals(5, fit.firstDroneGroupSize(), "Amount of Hornet EC-300's is incorrect")
            it.press(FitEditorSlotKeys.CarouselNext)
            assertEquals(3, fit.firstDroneGroupSize(), "Unexpected amount of Vespa EC-600's")
            it.press(FitEditorSlotKeys.CarouselNext)
            assertEquals(1, fit.firstDroneGroupSize(), "Unexpected amount of Wasp EC-900's")
        }
    }


    /**
     * Tests that the drone carousel doesn't crash if used when the ship can't fit drones (e.g. a strategic cruiser
     * after switching to a subsystem with no drones).
     */
    @Test
    fun whenUsingDronesWithDronelessFitCarouselDoesNotCrash() = runDesktopComposeUiTest {
        // In this test we don't actually have to use a strategic cruiser,
        // because we can just force drones into a fit that has no drones.

        val fit = newFit(
            shipName = "Onyx",
            isValid = { it.drones.capacity.total == 0 }
        )

        setApplicationContent {
            FitEditor(fit)
        }

        val eveData = TheorycrafterContext.eveData
        val droneType = eveData.droneType("Acolyte II")

        fits.modifyAndSave {
            fit.addDroneGroup(droneType, size = 5)
        }

        onSubtreeRootedAt(Nodes.FitEditor.droneRow(0))
            .assertAny(hasText(droneType.name, substring = true))
        onNode(Nodes.FitEditor.droneRow(0)).let {
            it.scrollToAndClick()
            it.press(FitEditorSlotKeys.CarouselNext)
        }
    }


}