package theorycrafter.fitting

import androidx.compose.runtime.*
import eve.data.Attributes
import eve.data.DamagePattern
import eve.data.DamageType
import eve.data.DroneType
import eve.data.utils.ValueByEnum
import eve.data.utils.valueByEnum


/**
 * A group of drones of the same type.
 *
 * Note that unless otherwise specified, the properties of a [DroneGroup] refer to a single drone. For example,
 */
@Stable
class DroneGroup internal constructor(


    /**
     * The fit this drone group is part of.
     */
    fit: Fit,


    /**
     * The context [Attributes].
     */
    attributes: Attributes,


    /**
     * The drone type.
     */
    type: DroneType,


    /**
     * The number of drones in the group.
     */
    size: Int


): ModuleOrDrone<DroneType>(fit, attributes, type){



    /**
     * The number of drones currently in the group.
     */
    var size: Int by mutableIntStateOf(size)
        internal set


    /**
     * Whether this drone group is currently active.
     */
    var active: Boolean by mutableStateOf(false)
        internal set


    /**
     * The total bandwidth of this drone group.
     */
    val totalBandwidth: Int
        get() = size * type.bandwidthUsed


    /**
     * The total volume of this drone group.
     */
    val totalVolume: Int
        get() = size * type.volume.toInt()


    /**
     * The bandwidth used by this drone group, equal to [totalBandwidth] when the group is active; 0 when inactive.
     */
    val totalUsedBandwidth: Int
        get() = if (active) totalBandwidth else 0


    /**
     * The drone's mass.
     */
    @Suppress("unused")
    val mass: AttributeProperty<Double>
        get() = property(attributes.mass)


    /**
     * The drone's inertia modifier.
     */
    @Suppress("unused")
    val inertiaModifier: AttributeProperty<Double>
        get() = property(attributes.inertiaModifier)


    /**
     * Drone speed when microwarpdriving, in meters/sec.
     */
    val mwdSpeed: AttributeProperty<Double>?
        get() = propertyOrNull(attributes.maxVelocity)


    /**
     * The speed when orbiting, in meters/sec.
     */
    @Suppress("unused")
    val orbitSpeed: AttributeProperty<Double>?
        get() = propertyOrNull(attributes.entityCruiseSpeed)


    /**
     * The radius when orbiting, in meters/sec.
     */
    @Suppress("unused")
    val orbitRadius: AttributeProperty<Double>?
        get() = propertyOrNull(attributes.entityFlyRange)


    /**
     * The property for the volley damage of each type done by this drone group; `null` if this drone group does no
     * damage of that type.
     */
    override val volleyDamageByType: ValueByEnum<DamageType, AttributeProperty<Double>?> by lazy {
        valueByEnum { damageType ->
            propertyOrNull(attributes.droneDamage[damageType])
        }
    }


    override val activationDuration: AttributeProperty<Double>
        get() = super.activationDuration!!  // Drones always have a duration


    override val optimalRange: AttributeProperty<Double>
        get() = super.optimalRange!!  // Drones always have an optimal range


    /**
     * The DPS pattern of a single drone in this group; `null` if none.
     */
    val dpsPattern: DamagePattern?
        get() {
            val volleyPattern = volleyPattern ?: return null
            val duration = activationDuration.doubleValue
            return DamagePattern {
                amountPerSecond(amountPerActivation = volleyPattern[it], durationMs = duration)
            }
        }


    /**
     * The total DPS pattern of this drone group; `null` if none.
     */
    val totalDpsPattern: DamagePattern?
        get() = dpsPattern?.let { it * size }


    /**
     * The damage per second done by a single drone in this group; `null` if none.
     */
    val dps: Double?
        get() = volleyDamage?.perSecond()


    /**
     * The total DPS of this drone group.
     */
    val totalDps: Double?
        get() = dps?.let { it * size }


    /**
     * The total volley damage of this drone group.
     */
    val totalVolleyDamage: Double?
        get() = volleyDamage?.let { it * size }


    /**
    * The [AttributeProperty] for the armor HP repaired by this armor-repairing drone in one activation.
     */
    val armorHpRepaired: AttributeProperty<Double>?
        get() = propertyOrNull(attributes.armorRepairAmount)


    /**
     * The amount of armor HP repaired by this armor-repairing drone in one activation.
     */
    override val armorHpRepairedValue: Double?
        get() = armorHpRepaired?.doubleValue


    /**
     * The drone group's defenses; note that all the hitpoint values refer to a single drone.
     */
    val defenses = ItemDefenses(
        item = this@DroneGroup,
        attributes = attributes,
        damagePattern = { DamagePattern.Uniform },
        localModules = ::emptyList,
        friendlyEffects = ::emptyList
    )


    override fun toString(): String {
        return "$size x ${super.toString()}"
    }


}
