/**
 * The tactical mode selector for the fit editor.
 */

package theorycrafter.ui.fiteditor

import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.testTag
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import compose.input.onKeyShortcut
import compose.widgets.GridScope
import eve.data.ShipType
import eve.data.TacticalModeType
import theorycrafter.TestTags
import theorycrafter.TheorycrafterContext
import theorycrafter.fitting.Fit
import theorycrafter.fitting.FittingEngine
import theorycrafter.fitting.TacticalMode
import theorycrafter.ui.TheorycrafterTheme
import theorycrafter.ui.fiteditor.effectcolumn.displayedTacticalModeEffect
import theorycrafter.ui.shortName
import theorycrafter.ui.widgets.SlotRow
import theorycrafter.utils.AutoSuggest
import theorycrafter.utils.onEmptyQueryReturn


/**
 * Returns the initial tactical mode that should be set on the given ship; `null` if none.
 */
fun initialTacticalMode(shipType: ShipType): TacticalModeType? {
    val tacticalModes = TheorycrafterContext.eveData.tacticalModeTypesOrNull(shipType) ?: return null
    return tacticalModes[TacticalModeType.Kind.DEFENSE]
}


/**
 * Returns the [Modifier] for key shortcuts that switch between tactical modes.
 */
fun Modifier.tacticalModeKeyShortcuts(fit: Fit, undoRedoQueue: FitEditorUndoRedoQueue): Modifier {
    val tacticalModes = TheorycrafterContext.eveData.tacticalModeTypesOrNull(fit.ship.type)
    if (tacticalModes == null)
        return this

    return this
        .onKeyShortcut(FitEditorKeyShortcuts.SetDefenseMode) {
            setTacticalModeAction(fit, tacticalModes[TacticalModeType.Kind.DEFENSE])?.let {
                undoRedoQueue.performAndAppend(it)
            }
        }
        .onKeyShortcut(FitEditorKeyShortcuts.SetSharpshooterMode) {
            setTacticalModeAction(fit, tacticalModes[TacticalModeType.Kind.SHARPSHOOTER])?.let {
                undoRedoQueue.performAndAppend(it)
            }
        }
        .onKeyShortcut(FitEditorKeyShortcuts.SetPropulsionMode) {
            setTacticalModeAction(fit, tacticalModes[TacticalModeType.Kind.PROPULSION])?.let {
                undoRedoQueue.performAndAppend(it)
            }
        }
}


/**
 * Returns a [FitEditingAction] that sets the tactical mode of the fit.
 */
private fun setTacticalModeAction(fit: Fit, newMode: TacticalModeType): FitEditingAction? {
    val prevMode = fit.tacticalMode!!.type
    if (prevMode == newMode)
        return null

    return object: FitEditingAction() {

        context(FitEditorUndoRedoContext)
        override fun FittingEngine.ModificationScope.performEdit() {
            fit.setTacticalMode(newMode)
        }

        context(FitEditorUndoRedoContext)
        override fun FittingEngine.ModificationScope.revertEdit() {
            fit.setTacticalMode(prevMode)
        }

    }
}


/**
 * Returns the auto-suggest for tactical modes.
 */
@Composable
private fun ShipType.rememberAutoSuggest(carousel: Carousel<TacticalModeType>): AutoSuggest<TacticalModeType> {
    val autoSuggest = TheorycrafterContext.autoSuggest.tacticalModes(this)

    return remember(autoSuggest, carousel) {
        autoSuggest.onEmptyQueryReturn { carousel.items }
    }
}


/**
 * A tactical mode selection widget.
 */
@Composable
private fun GridScope.GridRowScope.TacticalModeSelectorRow(
    carousel: Carousel<TacticalModeType>,
    onTacticalModeSelected: (TacticalModeType) -> Unit,
    onEditingCancelled: () -> Unit
) {
    val shipType = LocalFit.current.ship.type
    val autoSuggest = shipType.rememberAutoSuggest(carousel)

    ItemSelectorRow(
        onItemSelected = { onTacticalModeSelected(it) },
        onEditingCancelled = onEditingCancelled,
        autoSuggest = autoSuggest,
        autoSuggestItemToString = { it.shortName() },
        hint = "Tactical mode"
    )
}


/**
 * The row for a non-edited tactical mode.
 */
@Composable
private fun GridScope.GridRowScope.TacticalModeSlotContent(
    tacticalMode: TacticalMode,
    carousel: Carousel<TacticalModeType>
) {
    emptyCell(cellIndex = GridCols.STATE_ICON)  // No state icon
    emptyCell(cellIndex = GridCols.TYPE_ICON)
    cell(cellIndex = GridCols.NAME, colSpan = GridCols.EFFECT - GridCols.NAME) {
        CarouselSlotContent(
            carousel = carousel,
            targetState = tacticalMode.type,
            modifier = Modifier.fillMaxWidth(),
            text = { it.shortName() }
        )
    }
    cell(cellIndex = GridCols.EFFECT) {
        TextAndTooltipCell(displayedTacticalModeEffect(LocalFit.current, tacticalMode))
    }
    EmptyPriceCell()
}


/**
 * The tactical mode row.
 */
@Composable
private fun GridScope.TacticalModeRow(
    currentMode: TacticalMode,
    actions: TacticalModeActions,
) {
    val carousel = rememberTacticalModeCarousel(LocalFit.current.ship.type)

    SlotRow(
        modifier = Modifier
            .testTag(TestTags.FitEditor.TacticalModeSlot),
        modifierWhenNotEditing = Modifier
            .carouselShortcuts(carousel, currentMode.type) {
                // There's always a tactical mode
                actions.setTacticalMode(it, triggerCarouselAnimation = true)
            },
        invalidityReason = currentMode.illegalFittingReason,
        editedRowContent = { onEditingCompleted ->
            TacticalModeSelectorRow(
                carousel = carousel,
                onTacticalModeSelected = {
                    actions.setTacticalMode(it)
                    onEditingCompleted()
                },
                onEditingCancelled = onEditingCompleted
            )
        }
    ) {
        TacticalModeSlotContent(
            tacticalMode = currentMode,
            carousel = carousel
        )
    }
}


/**
 * Bundles the actions passed to [TacticalModeRow].
 */
private class TacticalModeActions(
    private val set: (TacticalModeType, triggerCarouselAnimation: Boolean) -> Unit,
) {

    fun setTacticalMode(tacticalMode: TacticalModeType, triggerCarouselAnimation: Boolean = false) {
        set(tacticalMode, triggerCarouselAnimation)
    }

}


/**
 * The title for the tactical mode section.
 */
@Composable
private fun tacticalModeSectionTitle() = buildAnnotatedString {
    append("Tactical Mode")
    append("  ")
    withStyle(TheorycrafterTheme.textStyles.fitEditorSectionTitleExtraInfo) {
        append("Shift-1·2·3")
    }
}


/**
 * The section for selecting the tactical mode.
 */
@Composable
fun GridScope.TacticalModeSection(
    firstRowIndex: Int,
    isFirst: Boolean,
    fit: Fit,
): Int {
    val tacticalMode = fit.tacticalMode ?: return 0

    // Section title
    SectionTitleRow(
        rowIndex = firstRowIndex,
        isFirst = isFirst,
        text = tacticalModeSectionTitle()
    )

    inRow(firstRowIndex + 1) {
        val undoRedoQueue = LocalFitEditorUndoRedoQueue.current
        TacticalModeRow(
            currentMode = tacticalMode,
            actions = remember(fit, undoRedoQueue) {
                TacticalModeActions(
                    set = { newTacticalMode, triggerCarouselAnimation ->
                        setTacticalModeAction(fit, newTacticalMode)?.let {
                            undoRedoQueue.performAndAppend(
                                it.withCarouselAnimation(triggerCarouselAnimation)
                            )
                        }
                    }
                )
            },
        )
    }

    return 2
}