/**
 * The parts of the fit editor that relate to hostile effects.
 */

package theorycrafter.ui.fiteditor

import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.text.AnnotatedString
import compose.widgets.GridScope
import eve.data.*
import theorycrafter.FitHandle
import theorycrafter.TestTags
import theorycrafter.TheorycrafterContext
import theorycrafter.fitting.Fit
import theorycrafter.fitting.FittingEngine
import theorycrafter.fitting.RemoteEffect
import theorycrafter.utils.AutoSuggest
import kotlin.math.max


/**
 * A [RemoteEffectFitActions] for hostile effects.
 */
private object HostileEffectFitActions: RemoteEffectFitActions() {


    override val Fit.effects: List<RemoteEffect>
        get() = hostileEffects


    override fun FittingEngine.ModificationScope.addRemoteEffect(
        targetFit: Fit,
        sourceFit: Fit,
        slotIndex: Int
    ): RemoteEffect {
        return targetFit.addHostileEffect(sourceFit, index = slotIndex)
    }


    override fun FittingEngine.ModificationScope.removeRemoteEffect(remoteEffect: RemoteEffect) {
        remoteEffect.target.removeHostileEffect(remoteEffect)
    }


}


/**
 * A [RemoteEffectFitActions] for friendly effects.
 */
private object FriendlyEffectFitActions: RemoteEffectFitActions() {


    override val Fit.effects: List<RemoteEffect>
        get() = friendlyEffects


    override fun FittingEngine.ModificationScope.addRemoteEffect(
        targetFit: Fit,
        sourceFit: Fit,
        slotIndex: Int
    ): RemoteEffect {
        return targetFit.addFriendlyEffect(sourceFit, index = slotIndex)
    }


    override fun FittingEngine.ModificationScope.removeRemoteEffect(remoteEffect: RemoteEffect) {
        remoteEffect.target.removeFriendlyEffect(remoteEffect)
    }


}


/**
 * The default number of drones to put in a remote drone effect.
 */
const val DEFAULT_EFFECT_DRONE_AMOUNT = 5


/**
 * Parses text from the clipboard into either a module or a drone remote effect.
 */
private fun EveData.clipboardTextToRemoteEffectSelection(text: String, isHostile: Boolean): RemoteEffectSelection? {
    fun EveItemType.isCorrectKind() = if (isHostile) isOffensive(this) else isAssistive(this)

    moduleFromClipboardText(text)?.let { moduleType ->
        if (moduleType.isCorrectKind())
            return RemoteEffectSelection.Module(moduleType)
    }

    droneGroupFromClipboardText(text)?.let { (droneType, amount) ->
        if (droneType.isCorrectKind())
            return RemoteEffectSelection.Drone(droneType, amount ?: DEFAULT_EFFECT_DRONE_AMOUNT)
    }

    return null
}


/**
 * Parses text from the clipboard into either a module or a drone hostile remote effect.
 */
private fun EveData.clipboardTextToHostileRemoteEffectSelection(text: String) =
    clipboardTextToRemoteEffectSelection(text, isHostile = true)


/**
 * Parses text from the clipboard into either a module or a drone friendly remote effect.
 */
private fun EveData.clipboardTextToFriendlyRemoteEffectSelection(text: String) =
    clipboardTextToRemoteEffectSelection(text, isHostile = false)


/**
 * Merges the fit handles and modules and drones into one auto-suggest result.
 */
@Composable
private fun mergeToEffectSelectionAutoSuggest(
    fitHandlesAutoSuggest: AutoSuggest<FitHandle>,
    modulesAndDronesAutoSuggest: AutoSuggest<ModuleOrDroneType>
): AutoSuggest<RemoteEffectSelection> {

    fun mergeLists(
        fitHandles: List<FitHandle>,
        modulesAndDrones: List<ModuleOrDroneType>
    ): List<RemoteEffectSelection> {
        return buildList {
            for (i in 0 until max(fitHandles.size, modulesAndDrones.size)) {
                if (i < modulesAndDrones.size) {
                    val itemType = modulesAndDrones[i]
                    add(
                        when (itemType) {
                            is ModuleType -> RemoteEffectSelection.Module(itemType)
                            is DroneType -> RemoteEffectSelection.Drone(itemType, DEFAULT_EFFECT_DRONE_AMOUNT)
                        }
                    )
                }
                if (i < fitHandles.size) {
                    add(RemoteEffectSelection.Fit(fitHandles[i]))
                }
            }
        }
    }

    return remember(fitHandlesAutoSuggest, modulesAndDronesAutoSuggest) {
        AutoSuggest { query ->
            val fits = fitHandlesAutoSuggest(query)
            val modulesAndDrones = modulesAndDronesAutoSuggest(query)

            if ((fits == null) && (modulesAndDrones == null))
                return@AutoSuggest null

            mergeLists(
                fitHandles = fits ?: emptyList(),
                modulesAndDrones = modulesAndDrones ?: emptyList()
            )
        }
    }
}


/**
 * Provides the content of the hostile effect slot row when the value is being edited.
 */
private val EditedHostileEffectRow = EditedRemoteEffectRow { scope, onRemoteEffectSelected, onEditingCancelled ->
    with(scope) {
        val remoteFitsAutoSuggest = rememberRemoteFitsAutoSuggest()
        val modulesAndDronesAutoSuggest = TheorycrafterContext.autoSuggest.hostileModulesAndDrones
        val effectSelectionAutoSuggest = mergeToEffectSelectionAutoSuggest(
            fitHandlesAutoSuggest = remoteFitsAutoSuggest,
            modulesAndDronesAutoSuggest = modulesAndDronesAutoSuggest
        )
        RemoteEffectSelectorRow(
            hint = "Fit name, module or drone",
            autoSuggest = effectSelectionAutoSuggest,
            onRemoteEffectSelected = onRemoteEffectSelected,
            onEditingCancelled = onEditingCancelled
        )
    }
}


/**
 * Provides the content of the friendly effect slot row when the value is being edited.
 */
private val EditedFriendlyEffectRow = EditedRemoteEffectRow { scope, onRemoteEffectSelected, onEditingCancelled ->
    with(scope) {
        val remoteFitsAutoSuggest = rememberRemoteFitsAutoSuggest()
        val modulesAndDronesAutoSuggest = TheorycrafterContext.autoSuggest.friendlyModulesAndDrones
        val effectSelectionAutoSuggest = mergeToEffectSelectionAutoSuggest(
            fitHandlesAutoSuggest = remoteFitsAutoSuggest,
            modulesAndDronesAutoSuggest = modulesAndDronesAutoSuggest
        )
        RemoteEffectSelectorRow(
            hint = "Fit name, module or drone",
            autoSuggest = effectSelectionAutoSuggest,
            onRemoteEffectSelected = onRemoteEffectSelected,
            onEditingCancelled = onEditingCancelled
        )
    }
}


/**
 * Returns the auto-suggest for fits to be the source of a [RemoteEffect].
 */
@Composable
private fun rememberRemoteFitsAutoSuggest(): AutoSuggest<FitHandle> {
    return remember {
        AutoSuggest { text: String ->
            TheorycrafterContext.queryFits(text)
        }
    }
}


/**
 * The section for specifying hostile effects.
 */
@Composable
fun GridScope.HostileEffectsSection(
    firstRowIndex: Int,
    isFirst: Boolean = false,
    fit: Fit,
): Int {
    return RemoteEffectsSection(
        firstRowIndex = firstRowIndex,
        isFirst = isFirst,
        fit = fit,
        remoteEffects = fit.hostileEffects,
        sectionTitle = AnnotatedString("Hostile Еffects"),
        remoteFitActions = HostileEffectFitActions,
        remoteEffectSlotTestTag = TestTags.FitEditor::hostileEffectRow,
        affectingModuleSlotTestTag = TestTags.FitEditor::hostileEffectAffectingModuleRow,
        affectingModuleChargeTestTag = TestTags.FitEditor::hostileEffectAffectingModuleChargeRow,
        affectingDroneSlotTestTag = TestTags.FitEditor::hostileEffectAffectingDroneRow,
        moduleEffectSlotTestTag = TestTags.FitEditor::hostileModuleEffectRow,
        moduleEffectChargeSlotTestTag = TestTags.FitEditor::hostileModuleEffectChargeRow,
        droneEffectSlotTestTag = TestTags.FitEditor::hostileDroneEffectRow,
        emptySlotText = "Empty Hostile Effect Slot",
        emptySlotTestTag = TestTags.FitEditor.EmptyHostileEffectRow,
        remoteEffectSelectionFromClipboardText = EveData::clipboardTextToHostileRemoteEffectSelection,
        editedRemoteEffectRow = EditedHostileEffectRow
    )
}


/**
 * The section for specifying friendly effects.
 */
@Composable
fun GridScope.FriendlyEffectsSection(
    firstRowIndex: Int,
    isFirst: Boolean = false,
    fit: Fit,
): Int {
    return RemoteEffectsSection(
        firstRowIndex = firstRowIndex,
        isFirst = isFirst,
        fit = fit,
        remoteEffects = fit.friendlyEffects,
        sectionTitle = AnnotatedString("Friendly Effects"),
        remoteFitActions = FriendlyEffectFitActions,
        remoteEffectSlotTestTag = TestTags.FitEditor::friendlyEffectRow,
        affectingModuleSlotTestTag = TestTags.FitEditor::friendlyEffectAffectingModuleRow,
        affectingModuleChargeTestTag = TestTags.FitEditor::friendlyEffectAffectingModuleChargeRow,
        affectingDroneSlotTestTag = TestTags.FitEditor::friendlyEffectAffectingDroneRow,
        moduleEffectSlotTestTag = TestTags.FitEditor::friendlyModuleEffectRow,
        moduleEffectChargeSlotTestTag = TestTags.FitEditor::friendlyModuleEffectChargeRow,
        droneEffectSlotTestTag = TestTags.FitEditor::friendlyDroneEffectRow,
        emptySlotText = "Empty Friendly Effect Slot",
        emptySlotTestTag = TestTags.FitEditor.EmptyFriendlyEffectRow,
        remoteEffectSelectionFromClipboardText = EveData::clipboardTextToFriendlyRemoteEffectSelection,
        editedRemoteEffectRow = EditedFriendlyEffectRow
    )
}
