/**
 * The UI showing a fit's defense stats: HP, resists etc.
 */

package theorycrafter.ui.fitstats

import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import compose.utils.EasyTooltipPlacement
import compose.widgets.GridScope
import compose.widgets.SimpleGrid
import compose.widgets.SingleLineText
import eve.data.*
import theorycrafter.fitting.Fit
import theorycrafter.fitting.ItemDefense
import theorycrafter.fitting.resistFactor
import theorycrafter.ui.TheorycrafterTheme
import theorycrafter.ui.fiteditor.ValueWithDescription
import theorycrafter.ui.fiteditor.ValueWithDescriptionTable
import theorycrafter.ui.tooltip
import theorycrafter.ui.widgets.PercentageView
import theorycrafter.utils.AttractAttentionOnValueChange
import theorycrafter.utils.DpOffsetY
import kotlin.math.roundToInt


/**
 * Displays a single resist (resonance) value.
 */
@Composable
private fun ResistView(
    damageType: DamageType,
    resonance: Double,
    hitpoints: Double,
    averageResistFactor: Double,
    modifier: Modifier = Modifier
) {
    val resistFactor = resistFactor(resonance)
    val ehp = hitpoints * resistFactor
    val ratio = resistFactor / averageResistFactor

    PercentageView(
        value = 1f - resonance.toFloat(),
        decimals = 1,
        colors = TheorycrafterTheme.colors.resistanceIndicatorColors(damageType),
        modifier = modifier
            .fillMaxWidth()
            .tooltip(
                placement = EasyTooltipPlacement.ElementBottomCenter(
                    offset = DpOffsetY(TheorycrafterTheme.spacing.xxxsmall)
                )
            ) {
                ValueWithDescriptionTable(
                    ValueWithDescription(resistFactor.asResistFactor(), "damage reduction"),
                    ValueWithDescription(ehp.asHitPoints(ehp = true), "against ${damageType.displayNameLowercase} damage"),
                    ValueWithDescription(
                        value = when {
                            resistFactor > averageResistFactor -> ratio.asMultiplicationFactor()
                            resistFactor < averageResistFactor -> (1/ratio).asMultiplicationFactor()
                            else -> "same"
                        },
                        description = when {
                            resistFactor > averageResistFactor -> "better than average"
                            resistFactor < averageResistFactor -> "worse than average"
                            else -> "as average"
                        }

                    )
                )
            }
    )
}


/**
 * A row of resists for a single defense type.
 */
@Composable
private fun GridScope.GridRowScope.ResistsRow(
    name: String,
    defense: ItemDefense,
) {
    val resonance = defense.resonances
    val resistFactor = defense.resistFactor
    val hp = defense.hp.value

    cell(0, modifier = Modifier.padding(end = 6.dp), contentAlignment = Alignment.CenterEnd) {
        SingleLineText(
            text = name,
            style = TheorycrafterTheme.textStyles.caption,
        )
    }

    @Composable
    fun cellFor(index: Int, damageType: DamageType) {
        cell(index) {
            ResistView(
                damageType = damageType,
                resonance = resonance[damageType].value,
                hitpoints = defense.hp.value,
                averageResistFactor = resistFactor,
                modifier = Modifier.fillMaxWidth(),
            )
        }
    }

    for (damageType in DamageType.entries)
        cellFor(1 + damageType.ordinal, damageType)

    val ehp = defense.ehp
    cell(5) {
        AttractAttentionOnValueChange(
            value = ehp,
            modifier = Modifier
                .tooltip(
                    placement = EasyTooltipPlacement.ElementCenterStart
                ) {
                    ValueWithDescriptionTable(
                        ValueWithDescription(resistFactor.asResistFactor(), "${defense.name.lowercase()} damage reduction"),
                        ValueWithDescription(hp.asHitPoints(withUnits = false), "raw hitpoints")
                    )
                }
        ) {
            SingleLineText(
                text = ehp.asHitPoints(ehp = true, withUnits = false),
                modifier = Modifier
                    .padding(start = TheorycrafterTheme.spacing.xsmall)
                    .align(Alignment.CenterStart),
            )
        }
    }
}


/**
 * UI showing the hitpoints stats.
 */
@Composable
private fun HpStats(fit: Fit) {
    with (fit.defenses) {
        val hp = hp
        val ehp = ehp

        StatsTable(
            columns = 3,
            Stat(
                label = "Effective",
                value = ehp.asHitPoints(ehp = true, withUnits = true),
                tooltipValues = listOf(
                    ValueWithDescription(value = ehp.roundToInt().toString(), description = "effective hitpoints")
                )
            ),
            Stat(
                label = "Raw",
                value = hp.asHitPoints(ehp = false, withUnits = true),
                tooltipValues = listOf(
                    ValueWithDescription(value = hp.roundToInt().toString(), description = "raw hitpoints")
                )
            ),
            RepairStat(fit)
        )
    }
}


/**
 * Returns the [Stat] for repairs.
 */
@Composable
private fun RepairStat(fit: Fit): Stat {
    return with(fit.defenses) {
        data class EhpRepair(
            val amount: Double,
            val defense: ItemDefense,
            val descriptionSuffix: String
        )

        val defenses = listOf(shield, armor, structure)
        val repairs = mutableListOf<EhpRepair>()
        for (defense in defenses) {
            repairs.add(
                EhpRepair(
                    amount = defense.ehpRepairedLocally,
                    defense = defense,
                    descriptionSuffix = "repaired locally"
                )
            )
            repairs.add(
                EhpRepair(
                    amount = defense.ehpRepairedByRemoteEffects,
                    defense = defense,
                    descriptionSuffix = "repaired remotely"
                )
            )
        }

        val hasShieldRepair = repairs.any { (it.amount > 0) && (it.defense == shield) }
        val hasArmorRepair = repairs.any { (it.amount > 0) && (it.defense == armor) }
        val hasStructureRepair = repairs.any { (it.amount > 0) && (it.defense == structure) }
        val includeShieldRegenInTotal = hasShieldRepair || (!hasArmorRepair && !hasStructureRepair)

        val shieldRegen = EhpRepair(
            amount = shield.peakRegenEhpPerSecond,
            defense = shield,
            descriptionSuffix = "peak regen" + (if (!includeShieldRegenInTotal) "*" else "")
        )
        val totalEhpRepairedPerSecond = repairs.sumOf { it.amount } +
                if (includeShieldRegenInTotal) shieldRegen.amount else 0.0

        // Put at the end of the shield section if included, otherwise put at the end
        if (includeShieldRegenInTotal)
            repairs.add(repairs.indexOfLast { it.defense == shield } + 1, shieldRegen)
        else
            repairs.add(shieldRegen)

        Stat(
            label = "Repaired",
            value = totalEhpRepairedPerSecond.asHitpointsPerSecond(ehp = true, withUnits = true),
            tooltipValues =
                repairs.mapNotNull {
                    if (it.amount == 0.0)
                        return@mapNotNull null
                    ValueWithDescription(
                        value = it.amount.roundToInt().toString(),
                        description = "${it.defense.name.lowercase()} EHP/s ${it.descriptionSuffix}"
                    )
                }
        )
    }
}


/**
 * UI showing the resist stats.
 */
@Composable
fun ResistStats(fit: Fit) {
    val defenses = fit.defenses
    SimpleGrid(
        columnWidths = listOf(TheorycrafterTheme.sizes.fitStatsCaptionColumnWidth) +
            List(4){ TheorycrafterTheme.sizes.fitStatsPercentageViewWidth } +  // One column per resist
            Dp.Unspecified,
        defaultRowModifier = Modifier.padding(bottom = 6.dp),
        defaultRowAlignment = Alignment.CenterVertically,
        defaultCellModifier = Modifier.padding(end = 4.dp).fillMaxWidth(),
    ) {
        row(0) {
            ResistsRow("Shield", defenses.shield)
        }
        row(1) {
            ResistsRow("Armor", defenses.armor)
        }
        row(2, modifier = Modifier.padding(bottom = 0.dp)) {  // Remove bottom padding from last row
            ResistsRow("Hull", defenses.structure)
        }
    }
}


/**
 * UI showing a fit's resistances, EHP etc.
 */
@Composable
fun DefenseStats(fit: Fit){
    Column(
        verticalArrangement = Arrangement.spacedBy(TheorycrafterTheme.spacing.small)
    ) {
        HpStats(fit)
        ResistStats(fit)
    }
}
