/**
 * 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.fits.FitHandle
import theorycrafter.TestTags
import theorycrafter.TheorycrafterContext
import theorycrafter.fitting.Fit
import theorycrafter.fitting.FittingEngine
import theorycrafter.fitting.RemoteEffect
import theorycrafter.utils.AutoSuggest
import theorycrafter.utils.interleave


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


    override val Fit.effects: List<RemoteEffect>
        get() = remoteEffects.hostile.allExcludingAuxiliary


    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() = remoteEffects.friendly.allExcludingAuxiliary


    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> {
    return remember(fitHandlesAutoSuggest, modulesAndDronesAutoSuggest) {
        AutoSuggest { query ->
            val fits = fitHandlesAutoSuggest(query)
            val modulesAndDrones = modulesAndDronesAutoSuggest(query)

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

            interleave(
                fits?.map { RemoteEffectSelection.Fit(it) } ?: emptyList(),
                modulesAndDrones?.map {
                    when (it) {
                        is ModuleType -> RemoteEffectSelection.Module(it)
                        is DroneType -> RemoteEffectSelection.Drone(it, DEFAULT_EFFECT_DRONE_AMOUNT)
                    }
                } ?: 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 = TheorycrafterContext.fitsAutoSuggest
        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 = TheorycrafterContext.fitsAutoSuggest
        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
        )
    }
}


/**
 * 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,
        remoteEffectSet = fit.remoteEffects.hostile,
        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,
        remoteEffectSet = fit.remoteEffects.friendly,
        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
    )
}
