package theorycrafter.ui.fiteditor

import androidx.compose.runtime.Composable
import androidx.compose.ui.input.key.Key
import compose.input.KeyShortcut
import compose.input.KeyboardModifierMatcher
import org.jetbrains.skiko.OS
import org.jetbrains.skiko.hostOs
import theorycrafter.ui.fiteditor.FitEditorKeyShortcuts.ChooseSuggestedValueAndSelectNextRow
import theorycrafter.ui.widgets.*


/**
 * The key shortcuts used in the fit editor.
 */
object FitEditorKeyShortcuts {


    /**
     * The key shortcut to toggle an item's online state.
     */
    val ToggleItemOnline = KeyShortcut(Key.O)


    /**
     * The key shortcut to toggle an item's overheated state.
     */
    val ToggleItemOverheated = KeyShortcut(Key.H)


    /**
     * The key shortcut(s) to toggle an item's primary state.
     */
    val ToggleItemPrimaryState = listOf(KeyShortcut(Key.T), KeyShortcut(Key.Spacebar))


    /**
     * The key shortcut(s) to toggle an item's enabled state.
     */
    val ToggleItemEnabled = ToggleItemPrimaryState + ToggleItemOnline


    /**
     * The key shortcut(s) to start editing an item.
     */
    val EditItem = KeyShortcut.anyOf(listOf(Key.Enter, Key.NumPadEnter, Key.F2))


    /**
     * The key shortcut that chooses the suggested item in the auto-suggest and moves selection to the next row.
     */
    val ChooseSuggestedValueAndSelectNextRow = KeyShortcut(Key.Tab)


    /**
     * The key shortcut(s) that chooses the suggested item in the auto-suggest.
     * This should include [ChooseSuggestedValueAndSelectNextRow].
     */
    val ChooseSuggestedValue = KeyShortcut.anyEnter() + ChooseSuggestedValueAndSelectNextRow


    /**
     * The key shortcut(s) that select the previous row.
     */
    val SelectPrevRow = listOf(
        KeyShortcut(Key.DirectionUp),
        KeyShortcut(Key.Tab, KeyboardModifierMatcher.Shift),
        KeyShortcut(Key.W)
    )


    /**
     * The key shortcut(s) that select the next row.
     */
    val SelectNextRow = listOf(
        KeyShortcut(Key.DirectionDown),
        KeyShortcut(Key.Tab, KeyboardModifierMatcher.None),
        KeyShortcut(Key.S)
    )


    /**
     * The key shortcut to clear a fitting slot (removing the item).
     */
    val ClearSlot = KeyShortcut.DeleteItem


    /**
     * The key shortcut modifier for adding an item of the same type as the selected one.
     */
    val AddOneItem = listOf(
        KeyShortcut('+'),  // Needed for keyboards where there's no dedicated '+' key (e.g. laptops)
        KeyShortcut(Key.Plus)  // Needed for testing
    )


    /**
     * The key shortcut modifier for removing an item of the same type as the selected one.
     */
    val RemoveOneItem = listOf(
        KeyShortcut('-'),  // Needed for keyboards where there's no dedicated '+' key (e.g. laptops)
        KeyShortcut(Key.Minus)  // Needed for testing
    )


    /**
     * The key shortcut to fit the previous item in the carousel.
     */
    val CarouselPrev = listOf(
        KeyShortcut(Key.DirectionLeft),
        KeyShortcut(Key.A)
    )


    /**
     * The key shortcut to fit the next item in the carousel.
     */
    val CarouselNext = listOf(
        KeyShortcut(Key.DirectionRight),
        KeyShortcut(Key.D)
    )


    /**
     * The key shortcut(s) to move the selection to the previous section in the fit editor.
     */
    val SelectionPrevSection = listOf(
        KeyShortcut(Key.PageUp),
        KeyShortcut(Key.DirectionUp, KeyboardModifierMatcher.Alt)
    )


    /**
     * The key shortcut(s) to move the selection to the next section in the fit editor.
     */
    val SelectionNextSection = listOf(
        KeyShortcut(Key.PageDown),
        KeyShortcut(Key.DirectionDown, KeyboardModifierMatcher.Alt)
    )


    /**
     * The key shortcut to move the selection to the beginning of the fit editor.
     */
    val SelectionFirst = KeyShortcut(Key.MoveHome)


    /**
     * The key shortcut to move the selection to the end of the fit editor.
     */
    val SelectionLast = KeyShortcut(Key.MoveEnd)


    /**
     * The key shortcut to show the "Go to Section" dialog.
     */
    val ShowGoToSectionDialog = KeyShortcut(Key.G)


    /**
     * The key shortcut(s) for switching to defense mode.
     */
    val SetDefenseMode =
        KeyShortcut.anyOf(listOf(Key.One, Key.NumPad1), KeyboardModifierMatcher.Shift)


    /**
     * The key shortcut(s) for switching to sharpshooter mode.
     */
    val SetSharpshooterMode =
        KeyShortcut.anyOf(listOf(Key.Two, Key.NumPad2), KeyboardModifierMatcher.Shift)


    /**
     * The key shortcut(s) for switching to propulsion mode.
     */
    val SetPropulsionMode =
        KeyShortcut.anyOf(listOf(Key.Three, Key.NumPad3), KeyboardModifierMatcher.Shift)


    /**
     * The key shortcut to cut an item to the clipboard.
     */
    val CutItemToClipboard = KeyShortcut.CutToClipboard


    /**
     * The key shortcut to copy an item to the clipboard.
     */
    val CopyItemToClipboard = KeyShortcut.CopyToClipboard


    /**
     * The key shortcut to paste an item from the clipboard.
     */
    val PasteItemFromClipboard = KeyShortcut.PasteFromClipboard


    /**
     * The key shortcut to show item info.
     */
    val ItemInfo = KeyShortcut(Key.I, KeyboardModifierMatcher.Command)


    /**
     * The key shortcut to add an item to the cargohold.
     */
    val AddToCargohold = KeyShortcut(Key.C)


    /**
     * The key shortcut to open the source of a remote effect in a new window.
     */
    val OpenRemoteEffectSource = KeyShortcut.anyEnter(KeyboardModifierMatcher.Command)


    /**
     * The key shortcut to mutate an item, or to edit an existing mutation.
     */
    val Mutate = KeyShortcut(Key.M, KeyboardModifierMatcher.Command)


    /**
     * The key shortcut to revert a mutated item to its base type.
     */
    val RevertToBase = KeyShortcut(Key.B, KeyboardModifierMatcher.Command)


    /**
     * The key shortcut to set the spoolup cycles of a triglavian module.
     */
    val SetSpoolupCycles = KeyShortcut(Key.S, KeyboardModifierMatcher.Command)


    /**
     * The key shortcut to set the number adaptation cycles of e.g. a Reactive Armor Hardener.
     */
    val SetAdaptationCycles = KeyShortcut(Key.A, KeyboardModifierMatcher.Command)


    /**
     * The key shortcut to activate all booster side effects.
     */
    val ActivateAllBoosterSideEffects = KeyShortcut(Key.Nine)


    /**
     * The key shortcut to deactivate all booster side effects.
     */
    val DeactivateAllBoosterSideEffects = KeyShortcut(Key.Zero)


    /**
     * The key shortcut to toggle the state of the Nth booster side effect.
     */
    val ToggleBoosterSideEffect = listOf(Key.One, Key.Two, Key.Three, Key.Four).map { KeyShortcut(it) }


    /**
     * The key shortcut to toggle weapons grouping.
     */
    val ToggleGroupWeapons = KeyShortcut(Key.G, KeyboardModifierMatcher.Command)


    /**
     * The shortcut for moving an item one slot up.
     */
    val MoveSlotUpKey = KeyShortcut(Key.DirectionUp, keyModifier = KeyboardModifierMatcher.Command)


    /**
     * The shortcut for moving an item one row down.
     */
    val MoveSlotDownKey = KeyShortcut(Key.DirectionDown, keyModifier = KeyboardModifierMatcher.Command)


    /**
     * The shortcut for toggling whether the prices column is visible.
     */
    val TogglePriceColumnKey = KeyShortcut(Key.P, keyModifier = KeyboardModifierMatcher.cmd().shift())


    /**
     * The alternate shortcut for toggling whether the prices column is visible.
     */
    val TogglePriceColumnKeyAlternate = KeyShortcut(Key.F4)


}


/**
 * Information about a section for the Go to Section dialog.
 */
class SectionSelectionShortcut(
    val key: Key,
    val name: String,
    val section: (SlotSelectionModel) -> SlotSelectionModel.Section<*>
)


/**
 * The section selection shortcuts.
 */
val SectionSelectionShortcuts = listOf(
    SectionSelectionShortcut(Key.T, "Tactical Mode", SlotSelectionModel::TacticalModeSection),
    SectionSelectionShortcut(Key.S, "Subsystems", SlotSelectionModel::SubsystemsSection),
    SectionSelectionShortcut(Key.One, "High Slots", SlotSelectionModel::HighSlotsSection),
    SectionSelectionShortcut(Key.Two, "Medium Slots", SlotSelectionModel::MediumSlotsSection),
    SectionSelectionShortcut(Key.Three, "Low Slots", SlotSelectionModel::LowSlotsSection),
    SectionSelectionShortcut(Key.Four, "Rigs", SlotSelectionModel::RigsSection),
    SectionSelectionShortcut(Key.D, "Drones", SlotSelectionModel::DronesSection),
    SectionSelectionShortcut(Key.I, "Implants", SlotSelectionModel::ImplantsSection),
    SectionSelectionShortcut(Key.B, "Boosters", SlotSelectionModel::BoostersSection),
    SectionSelectionShortcut(Key.C, "Cargo", SlotSelectionModel::CargoholdSection),
    SectionSelectionShortcut(Key.O, "Command Fits", SlotSelectionModel::CommandEffectsSection),
    SectionSelectionShortcut(Key.H, "Hostile Effects", SlotSelectionModel::HostileEffectsSection),
    SectionSelectionShortcut(Key.F, "Friendly Effects", SlotSelectionModel::FriendlyEffectsSection),
    SectionSelectionShortcut(Key.N, "Incoming Damage", SlotSelectionModel::IncomingDamageSection),
    SectionSelectionShortcut(Key.E, "Environment", SlotSelectionModel::EnvironmentEffectsSection),
).associateBy { it.key }


/**
 * The legend of the keyboard shortcuts in the fit editor.
 */
private val FIT_EDITOR_KEY_SHORTCUTS_TOOLTIP_CONTENTS = listOf(
    KeyShortcutDescription(
        description = "Start editing slot",
        DisplayedKeyShortcut("enter", verticalShiftMultiplier = LowercaseTextShiftMultiplier),
        DisplayedKeyShortcut("F2")
    ),
    KeyShortcutDescription(
        description = "Clear slot",
        DisplayedKeyShortcut("del", verticalShiftMultiplier = 0.1f), // 'del' is taller than regular text
        DisplayedKeyShortcut("⌫", verticalShiftMultiplier = 0.05f)
    ),
    KeyShortcutDescription(
        description = "Scroll through item variants",
        DisplayedKeyShortcut("←", verticalShiftMultiplier = ArrowsVerticalShiftMultiplier),
        DisplayedKeyShortcut("→", verticalShiftMultiplier = ArrowsVerticalShiftMultiplier)
    ),
    KeyShortcutDescription(
        description = "Toggle primary state",
        DisplayedKeyShortcut("space", verticalShiftMultiplier = LowercaseTextShiftMultiplier),
        DisplayedKeyShortcut("T")
    ),
    KeyShortcutDescription("Toggle online state", "O"),
    KeyShortcutDescription("Toggle heat state", "H"),
    KeyShortcutDescription(
        description = "Adjust number of items in group",
        DisplayedKeyShortcut("+", verticalShiftMultiplier = 0.2f),
        DisplayedKeyShortcut("-", verticalShiftMultiplier = when (hostOs){
            OS.MacOS -> 0.2f
            OS.Windows -> 0.3f
            else -> null
        })
    )
)


/**
 * The tooltip displaying the fit editor key shortcuts.
 */
@Composable
fun FitEditorKeyShortcutsTooltip() {
    KeyShortcutsTooltip(FIT_EDITOR_KEY_SHORTCUTS_TOOLTIP_CONTENTS)
}

