/**
 * Determines the value to be displayed in the "Effect" column for tactical modes.
 */

package theorycrafter.ui.fiteditor.effectcolumn

import androidx.compose.runtime.Composable
import eve.data.AttributeModifier.Operation
import eve.data.DamageType
import eve.data.TacticalModeType
import eve.data.typeid.isConfessor
import eve.data.typeid.isHecate
import eve.data.typeid.isJackdaw
import eve.data.typeid.isSvipul
import theorycrafter.fitting.AppliedEffect
import theorycrafter.fitting.AttributeProperty
import theorycrafter.fitting.Fit
import theorycrafter.fitting.TacticalMode
import theorycrafter.ui.widgets.TextAndTooltip
import theorycrafter.utils.with


/**
 * All the information we need to display a [TacticalMode]'s effect.
 */
private class TacticalModeInfo(
    override val fit: Fit,
    val tacticalMode: TacticalMode
): AffectingItemInfo{

    // We're only displaying tactical mode properties, not applied effects
    override val appliedEffects: Map<AttributeProperty<*>, Collection<AppliedEffect>>
        get() = error("Tactical modes don't display their applied effects")

}


/**
 * Returns the displayed effect for the given tactical mode.
 */
@Composable
fun displayedTacticalModeEffect(fit: Fit, tacticalMode: TacticalMode): TextAndTooltip? {
    val shipType = fit.ship.type
    val tacticalModeKind = tacticalMode.type.kind
    val tacticalModeInfo = TacticalModeInfo(fit, tacticalMode)
    return with(TacticalModeEffectSources, tacticalModeInfo) {
        when {
            shipType.isJackdaw() -> when (tacticalModeKind){
                TacticalModeType.Kind.DEFENSE -> withMergedMainSource(
                    mainSource = SHIELD_RESISTANCE_BONUS_PROPERTY,
                    SIGNATURE_RADIUS_BONUS_PROPERTY
                )
                TacticalModeType.Kind.SHARPSHOOTER -> withMergedMainSource(
                    mainSource = ROCKET_AND_LIGHT_MISSILE_DAMAGE_BONUS_PROPERTY,
                    ROCKET_AND_LIGHT_MISSILE_VELOCITY_BONUS_PROPERTY,
                    SENSOR_STRENGTH_BONUS_PROPERTY,
                    TARGETING_RANGE_BONUS_PROPERTY,
                    EWAR_RESISTANCE_BONUS_PROPERTY,
                )
                TacticalModeType.Kind.PROPULSION -> withMergedMainSource(
                    mainSource = MAX_VELOCITY_BONUS_PROPERTY,
                    INERTIA_MODIFIER_BONUS_PROPERTY
                )
            }
            shipType.isSvipul() -> when (tacticalModeKind){
                TacticalModeType.Kind.DEFENSE -> withMergedMainSource(
                    mainSource = SHIELD_AND_ARMOR_RESISTANCE_BONUS_PROPERTY,
                    MICROWARPDRIVE_SIGNATURE_RADIUS_BONUS_PROPERTY,
                    REMOTE_SHIELD_BOOSTER_AMOUNT_BONUS_PROPERTY,
                    REMOTE_SHIELD_BOOSTER_CAPACITOR_NEED_BONUS_PROPERTY,
                )
                TacticalModeType.Kind.SHARPSHOOTER -> withMergedMainSource(
                    mainSource = SMALL_PROJECTILE_TURRET_DAMAGE_BONUS_PROPERTY,
                    SMALL_PROJECTILE_TURRET_TRACKING_BONUS_PROPERTY,
                    SENSOR_STRENGTH_BONUS_PROPERTY,
                    TARGETING_RANGE_BONUS_PROPERTY,
                    EWAR_RESISTANCE_BONUS_PROPERTY,
                )
                TacticalModeType.Kind.PROPULSION -> withMergedMainSource(
                    mainSource = AFTERBURNER_AND_MICROWARPDRIVE_SPEED_BOOST_BONUS_PROPERTY,
                    INERTIA_MODIFIER_BONUS_PROPERTY
                )
            }
            shipType.isConfessor() -> when (tacticalModeKind){
                TacticalModeType.Kind.DEFENSE -> withMergedMainSource(
                    mainSource = ARMOR_RESISTANCE_BONUS_PROPERTY,
                    SIGNATURE_RADIUS_BONUS_PROPERTY,
                    REMOTE_ARMOR_REPAIRER_AMOUNT_BONUS_PROPERTY,
                    REMOTE_ARMOR_REPAIRER_CAPACITOR_NEED_BONUS_PROPERTY,
                )
                TacticalModeType.Kind.SHARPSHOOTER -> withMergedMainSource(
                    mainSource = SMALL_ENERGY_TURRET_DAMAGE_BONUS_PROPERTY,
                    SMALL_ENERGY_TURRET_OPTIMAL_RANGE_BONUS_PROPERTY,
                    SENSOR_STRENGTH_BONUS_PROPERTY,
                    TARGETING_RANGE_BONUS_PROPERTY,
                    EWAR_RESISTANCE_BONUS_PROPERTY,
                )
                TacticalModeType.Kind.PROPULSION -> withMergedMainSource(
                    mainSource = AFTERBURNER_AND_MICROWARPDRIVE_SPEED_BOOST_BONUS_PROPERTY,
                    INERTIA_MODIFIER_BONUS_PROPERTY
                )
            }
            shipType.isHecate() -> when (tacticalModeKind){
                TacticalModeType.Kind.DEFENSE -> withMergedMainSource(
                    mainSource = ARMOR_AND_HULL_RESISTANCE_BONUS_PROPERTY,
                    ARMOR_REPAIRER_DURATION_BONUS_PROPERTY
                )
                TacticalModeType.Kind.SHARPSHOOTER -> withMergedMainSource(
                    mainSource = SMALL_HYBRID_TURRET_DAMAGE_BONUS_PROPERTY,
                    SMALL_HYBRID_TURRET_OPTIMAL_RANGE_BONUS_PROPERTY,
                    SENSOR_STRENGTH_BONUS_PROPERTY,
                    TARGETING_RANGE_BONUS_PROPERTY,
                    EWAR_RESISTANCE_BONUS_PROPERTY,
                )
                TacticalModeType.Kind.PROPULSION -> withMergedMainSource(
                    mainSource = MICROWARPDRIVE_SPEED_BOOST_BONUS_PROPERTY,
                    MICROWARPDRIVE_CAPACITOR_NEED_BONUS_PROPERTY,
                    INERTIA_MODIFIER_BONUS_PROPERTY
                )
            }
            else -> null
        }
    }
}


/**
 * A [DisplayedEffectSource] for displaying the value of a tactical mode property.
 */
private class TacticalModePropertyEffectSource<T: Any>(


    /**
     * Returns the property.
     */
    val property: @Composable (TacticalMode) -> AttributeProperty<T>?,


    /**
     * A very short description of the property.
     */
    description: String,


    /**
     * Formats the property's value.
     */
    private val formatValue: (T, isCellDisplay: Boolean) -> String?


): DisplayedEffectSource<TacticalModeInfo>(description = description){


    @Composable
    override fun valueOrMissingText(
        fit: Fit,
        affectingItemInfo: TacticalModeInfo,
        isCellDisplay: Boolean
    ): ValueOrMissing?{
        val tacticalMode = affectingItemInfo.tacticalMode

        val property = property(tacticalMode) ?: return null
        val value = property.value
        val valueText = formatValue(value, isCellDisplay)
        return valueText.valueOr(null)
    }


}


/**
 * Returns the text for the given tactical mode property value.
 */
private fun propertyValueAsText(value: Double, isCellDisplay: Boolean) =
    effectMagnitudeAsText(
        magnitude = value,
        operation = Operation.POST_DIVIDE,
        isCellDisplay = isCellDisplay,
        absoluteValue = { _, _, _ -> error("${Operation.POST_DIVIDE} doesn't use absoluteValue") },
        withSign = isCellDisplay
    )


/**
 * The sources of tactical mode effects.
 */
private object TacticalModeEffectSources{


    /**
     * Returns a [TacticalModePropertyEffectSource] for a [Double] property
     */
    private fun doubleProperty(
        property: @Composable (TacticalMode) -> AttributeProperty<Double>?,
        description: String,
        invertValue: Boolean = false
    ) = TacticalModePropertyEffectSource(
        property = property,
        description = description,
        formatValue = { value, isCellDisplay ->
            propertyValueAsText(
                value = if (invertValue) value.invert(Operation.POST_DIVIDE) else value,
                isCellDisplay = isCellDisplay
            )
        }
    )


    /**
     * Bonus to some kind of resistances.
     */
    private fun resistanceBonusProperty(description: String) = doubleProperty(
        property = { mode ->
            mode.resonanceBonusDiv[DamageType.EM]  // Assume they're all the same
        },
        description = description,
        invertValue = true  // Convert resonance to resist
    )


    /**
     * Bonus to all shield resistances.
     */
    val SHIELD_RESISTANCE_BONUS_PROPERTY = resistanceBonusProperty(
        description = "bonus to all shield resistances"
    )


    /**
     * Bonus to all armor resistances.
     */
    val ARMOR_RESISTANCE_BONUS_PROPERTY = resistanceBonusProperty(
        description = "bonus to all armor resistances"
    )


    /**
     * Bonus to all shield and armor resistances.
     */
    val SHIELD_AND_ARMOR_RESISTANCE_BONUS_PROPERTY = resistanceBonusProperty(
        description = "bonus to all shield and armor resistances"
    )


    /**
     * Bonus to all armor and hull resistances.
     */
    val ARMOR_AND_HULL_RESISTANCE_BONUS_PROPERTY = resistanceBonusProperty(
        description = "bonus to all armor and hull resistances"
    )


    /**
     * Bonus to signature radius.
     */
    val SIGNATURE_RADIUS_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.signatureRadiusBonusDiv },
        description = "reduction in signature radius",
        invertValue = true
    )


    /**
     * Bonus to some kind of weapon damage.
     */
    private fun damageBonusProperty(description: String) = doubleProperty(
        property = { mode -> mode.damageBonusDiv },
        description = description
    )


    /**
     * Bonus to rocket and light missile damage.
     */
    val ROCKET_AND_LIGHT_MISSILE_DAMAGE_BONUS_PROPERTY = damageBonusProperty(
        description = "bonus to Rocket and Light Missile damage",
    )


    /**
     * Bonus to small projectile turret damage.
     */
    val SMALL_PROJECTILE_TURRET_DAMAGE_BONUS_PROPERTY = damageBonusProperty(
        description = "bonus to small projectile turret damage"
    )


    /**
     * Bonus to small energy turret damage.
     */
    val SMALL_ENERGY_TURRET_DAMAGE_BONUS_PROPERTY = damageBonusProperty(
        description = "bonus to small energy turret damage"
    )


    /**
     * Bonus to small hybrid turret damage.
     */
    val SMALL_HYBRID_TURRET_DAMAGE_BONUS_PROPERTY = damageBonusProperty(
        description = "bonus to small hybrid turret damage"
    )


    /**
     * Bonus to weapon optimal range.
     */
    fun optimalRangeBonusProperty(description: String) = doubleProperty(
        property = { mode -> mode.maxRangeBonusDiv },
        description = description
    )


    /**
     * Bonus to rocket and light missile velocity.
     */
    val ROCKET_AND_LIGHT_MISSILE_VELOCITY_BONUS_PROPERTY = optimalRangeBonusProperty(
        description = "bonus to Rocket and Light Missile velocity"
    )


    /**
     * Bonus to small energy turret optimal range.
     */
    val SMALL_ENERGY_TURRET_OPTIMAL_RANGE_BONUS_PROPERTY = optimalRangeBonusProperty(
        description = "bonus to small energy turret optimal range"
    )


    /**
     * Bonus to small hybrid turret optimal range.
     */
    val SMALL_HYBRID_TURRET_OPTIMAL_RANGE_BONUS_PROPERTY = optimalRangeBonusProperty(
        description = "bonus to small hybrid turret optimal range"
    )


    /**
     * Bonus to small projectile turret tracking range.
     */
    val SMALL_PROJECTILE_TURRET_TRACKING_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.trackingBonusDiv },
        description = "bonus to small projectile turret tracking"
    )


    /**
     * Bonus to sensor strength.
     */
    val SENSOR_STRENGTH_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.sensorStrengthBonusDiv.values.maxBy { it?.value ?: 0.0 } },
        description = "bonus to sensor strength"
    )


    /**
     * Bonus to targeting range.
     */
    val TARGETING_RANGE_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.targetingRangeBonusDiv },
        description = "bonus to targeting range"
    )


    /**
     * Bonus to resistance to Sensor Dampeners and Weapon Disruptors.
     */
    val EWAR_RESISTANCE_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.ewarResistanceBonusDiv },
        description = "bonus to ewar resistance",
        invertValue = true
    )


    /**
     * Bonus to velocity, or AB/MWD speed boost.
     */
    private fun velocityProperty(description: String) = doubleProperty(
        property = { mode -> mode.velocityBonusDiv },
        description = description,
    )


    /**
     * Bonus to ship maximum velocity.
     */
    val MAX_VELOCITY_BONUS_PROPERTY = velocityProperty(
        description = "bonus to ship maximum velocity"
    )


    /**
     * Bonus to Afterburner and Microwarpdrive speed boost.
     */
    val AFTERBURNER_AND_MICROWARPDRIVE_SPEED_BOOST_BONUS_PROPERTY = velocityProperty(
        description = "bonus to AB and MWD speed boost"
    )


    /**
     * Bonus to Microwarpdrive speed boost.
     */
    val MICROWARPDRIVE_SPEED_BOOST_BONUS_PROPERTY = velocityProperty(
        description = "bonus to MWD speed boost"
    )


    /**
     * Bonus to agility.
     */
    val INERTIA_MODIFIER_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.agilityBonusDiv },
        description = "bonus to agility",
        invertValue = true
    )


    /**
     * Reduction in Microwarpdrive signature radius bloom.
     */
    val MICROWARPDRIVE_SIGNATURE_RADIUS_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.microwarpdriveSignaturePenaltyBonusDiv },
        description = "reduction in MWD signature radius penalty",
        invertValue = true
    )


    /**
     * Bonus to armor repairer duration.
     */
    val ARMOR_REPAIRER_DURATION_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.armorRepairerDurationBonusDiv },
        description = "reduction in armor repairer duration",
        invertValue = true
    )


    /**
     * Bonus to Microwarpdrive capacitor need.
     */
    val MICROWARPDRIVE_CAPACITOR_NEED_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.microwarpdriveCapacitorBonusDiv },
        description = "reduction in MWD capacitor need",
        invertValue = true
    )


    /**
     * Bonus to remote shield booster amount.
     */
    val REMOTE_SHIELD_BOOSTER_AMOUNT_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.remoteRepairAmountPostDiv },
        description = "bonus to remote shield booster repair amount",
    )


    /**
     * Bonus to remote armor repairer amount.
     */
    val REMOTE_ARMOR_REPAIRER_AMOUNT_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.remoteRepairAmountPostDiv },
        description = "bonus to remote armor repairer repair amount",
    )


    /**
     * Bonus to remote shield booster capacitor need.
     */
    val REMOTE_SHIELD_BOOSTER_CAPACITOR_NEED_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.remoteRepairCapacitorCostPostDiv },
        description = "reduction in remote shield booster capacitor need",
        invertValue = true
    )


    /**
     * Bonus to remote armor repairer capacitor need.
     */
    val REMOTE_ARMOR_REPAIRER_CAPACITOR_NEED_BONUS_PROPERTY = doubleProperty(
        property = { mode -> mode.remoteRepairCapacitorCostPostDiv },
        description = "reduction in remote armor repairer capacitor need",
        invertValue = true
    )


}
