/**
 * A collection of small utilities that don't have a better home.
 */

package theorycrafter.utils

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.widthIn
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.ParagraphStyle
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.text.withStyle
import androidx.compose.ui.unit.dp
import compose.utils.EasyTooltipPlacement
import compose.utils.TooltipDefaults
import eve.data.*
import theorycrafter.TheorycrafterContext
import theorycrafter.ui.TheorycrafterTheme
import theorycrafter.ui.tooltip
import java.awt.Frame
import kotlin.math.PI


/**
 * The UI displayed in the auto-suggest dropdown menu when there are no matches.
 */
@Composable
fun NoMatches(
    text: String = "No matches",
    modifier: Modifier = Modifier
) {
    Box(
        modifier = Modifier
            .padding(
                horizontal = TheorycrafterTheme.spacing.horizontalEdgeMargin,
                vertical = TheorycrafterTheme.spacing.large
            )
            .then(modifier)
        ,
        contentAlignment = Alignment.TopCenter,
    ) {
        Text(text)
    }
}


/**
 * Returns the [AnnotatedString] to display for the given [Traits].
 */
fun Traits.displayString() = buildAnnotatedString {

    fun BonusValue.displayText() = when (unit) {
        BonusUnit.METERS -> withUnitsAndSign(number = amount, units = "m", withSign = true, withUnits = true)
        BonusUnit.KILOGRAMS -> withUnitsAndSign(number = amount, units = "kg", withSign = true, withUnits = true)
        BonusUnit.MULTIPLY -> "x$amount"
        BonusUnit.PERCENT -> "${amount}%"
        BonusUnit.NUMBER -> withUnitsAndSign(number = amount, units = "", withSign = true, withUnits = false)
    }

    fun AnnotatedString.Builder.appendBonus(bonus: Bonus) {
        bonus.value.let { value ->
            val textAnnotatedString = bonus.text.simpleStyleTagsToAnnotatedString()
            if (value == null)
                append(textAnnotatedString)
            else {
                append(value.displayText())
                append(" ")
                append(textAnnotatedString)
            }
        }
    }

    val eveData = TheorycrafterContext.eveData
    val newParagraph = ParagraphStyle()
    val sectionTitleStyle = TheorycrafterTheme.textStyles.tooltipHeading.toSpanStyle()
    val sectionStyle = ParagraphStyle()

    // Per-skill section
    for ((skillId, bonuses) in perSkill) {
        val skill = eveData.skillType(skillId)
        withStyle(newParagraph) {
            if (length != 0)
                appendLine()
            withStyle(sectionTitleStyle) {
                append("${skill.name} bonuses (per skill level)")
            }
        }
        for (bonus in bonuses) {
            withStyle(sectionStyle) {
                appendBonus(bonus)
            }
        }
    }

    if (role.isNotEmpty()) {
        withStyle(newParagraph) {
            if (length != 0)
                appendLine()
            withStyle(sectionTitleStyle) {
                append("Role bonuses")
            }
        }
        for (bonus in role) {
            withStyle(sectionStyle) {
                appendBonus(bonus)
            }
        }
    }

    if (misc.isNotEmpty()) {
        withStyle(newParagraph) {
            if (length != 0)
                appendLine()
            withStyle(sectionTitleStyle) {
                append("Additional bonuses")
            }
        }
        for (bonus in misc) {
            withStyle(sectionStyle) {
                appendBonus(bonus)
            }
        }
    }
}.trimNewlinesFromEnd()


/**
 * A tooltip [Modifier] for displaying a ship's traits.
 */
fun Modifier.shipTypeTraitsTooltip(
    shipType: ShipType,
    delayMillis: Int = TooltipDefaults.ShowDelayMillis,
    tooltipPlacement: EasyTooltipPlacement = TooltipDefaults.Placement,
) = tooltip(
    annotatedText = shipType.traits?.let {
        { it.displayString() }
    },
    delayMillis = delayMillis,
    placement = tooltipPlacement,
    modifier = Modifier.widthIn(max = 400.dp)
)


/**
 * The ordering of metagroups.
 * A mapping from meta group id to its index in the ordering.
 */
val MetaGroupOrder: Map<Int, Int> by lazy {
    with(TheorycrafterContext.eveData.metaGroups) {
        listOf(tech1, tech2, storyline, faction, deadspace, officer)
            .mapIndexed { index, metaGroup ->
                metaGroup.id to index
            }
            .toMap()
    }
}


/**
 * Converts radians to degrees.
 */
fun Double.rad2deg() = this * 180.0 / PI


/**
 * Converts degrees to radians.
 */
fun Double.deg2rad() = this * PI / 180.0


/**
 * The non-breaking space character.
 */
const val NBSP = ' '


/**
 * Returns the weighted average of two values.
 */
fun weightedAverage(a: Double, b: Double, weight: Double = 0.5) = weight*a + (1-weight)*b


/**
 * De-iconifies the frame, if needed, and brings it to the front.
 */
fun Frame.deiconifyAndBringToFront() {
    extendedState = Frame.NORMAL  // De-iconifies the window. On Windows, toFront() doesn't work on iconified windows
    toFront()
}
