package theorycrafter.ui

import androidx.compose.foundation.Image
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.defaultMinSize
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.size
import androidx.compose.material.Icon
import androidx.compose.material.LocalContentAlpha
import androidx.compose.material.LocalContentColor
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.automirrored.outlined.*
import androidx.compose.material.icons.filled.Info
import androidx.compose.material.icons.outlined.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.DefaultAlpha
import androidx.compose.ui.graphics.isSpecified
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.graphics.takeOrElse
import androidx.compose.ui.graphics.vector.ImageVector
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.semantics.*
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import compose.widgets.SingleLineText
import eve.data.*
import org.jetbrains.compose.resources.*
import theorycrafter.AnalyticsConsent
import theorycrafter.TheorycrafterContext
import theorycrafter.sharedapp.generated.resources.*
import theorycrafter.fitting.Module
import theorycrafter.utils.thenIf
import java.util.MissingResourceException


/**
 * Holds the icons used by the app.
 */
object Icons {


    /**
     * The icon for an EVE item, if it has one.
     */
    @Composable
    fun EveItemType(
        itemType: EveItemType,
        modifier: Modifier = Modifier
    ) {
        if (itemType.hasIcon) {
            EveResourceImage(
                eveObject = itemType,
                contentDescription = itemType.name,
                modifier = modifier
                    .thenIf(itemType.isIconRendering) {
                        clip(TheorycrafterTheme.eveTypeRenderingClip)
                    }
            )
        }
    }


    /**
     * The icon for an EVE market group, if it has one.
     */
    @Composable
    fun MarketGroup(
        marketGroup: MarketGroup,
        modifier: Modifier = Modifier
    ) {
        if (marketGroup.hasIcon) {
            EveResourceImage(
                eveObject = marketGroup,
                modifier = modifier,
                contentDescription = marketGroup.name,
            )
        }
    }


    /**
     * The icon for a module slot type.
     */
    @Composable
    fun ModuleSlotType(
        slotType: ModuleSlotType,
        thinStyle: Boolean = false,
        color: Color = Color.Unspecified,
        modifier: Modifier = Modifier,
    ) {
        val resource = when (slotType) {
            ModuleSlotType.LOW -> if (thinStyle) Res.drawable.slot_low_thin else Res.drawable.slot_low
            ModuleSlotType.MEDIUM -> if (thinStyle) Res.drawable.slot_medium_thin else Res.drawable.slot_medium
            ModuleSlotType.HIGH -> if (thinStyle) Res.drawable.slot_high_thin else Res.drawable.slot_high
            ModuleSlotType.RIG -> if (thinStyle) Res.drawable.slot_rig_thin else Res.drawable.slot_rig
        }
        Image(
            painter = painterResource(resource),
            contentDescription = "${slotType.name} slot",
            colorFilter = ColorFilter.tint(color.takeOrElse { LocalContentColor.current }),
            modifier = modifier
        )
    }


    /**
     * The icon for a drone slot type.
     */
    @Composable
    fun DroneSlot(
        color: Color = Color.Unspecified,
        modifier: Modifier = Modifier,
    ) {
        Image(
            painter = painterResource(Res.drawable.slot_drone),
            contentDescription = "Drone slot",
            colorFilter = ColorFilter.tint(color.takeOrElse { LocalContentColor.current }),
            modifier = modifier
        )
    }


    /**
     * The icon for a damage type.
     */
    @Composable
    fun DamageType(
        damageType: DamageType,
        modifier: Modifier = Modifier
    ) {
        val resource = when (damageType) {
            DamageType.EM -> Res.drawable.dmg_em
            DamageType.THERMAL -> Res.drawable.dmg_thermal
            DamageType.KINETIC -> Res.drawable.dmg_kinetic
            DamageType.EXPLOSIVE -> Res.drawable.dmg_explosive
        }
        Image(
            painter = painterResource(resource),
            contentDescription = damageType.displayName,
            modifier = modifier
        )
    }


    /**
     * The icon for a "Copy" action.
     */
    @Composable
    fun Copy() {
        Icon(TheorycrafterTheme.iconStyle.ContentCopy)
    }


    /**
     * The icon for a "Copy with options" action.
     */
    @Composable
    fun CopyWithOptions() {
        Icon(vectorResource(Res.drawable.copy_with_options))
    }


    /**
     * The icon for a "Paste" action.
     */
    @Composable
    fun Paste() {
        Icon(TheorycrafterTheme.iconStyle.ContentPaste)
    }


    /**
     * The icon for a "Cut" action.
     */
    @Composable
    fun Cut() {
        Icon(TheorycrafterTheme.iconStyle.ContentCut)
    }


    /**
     * The icon for a "Duplicate" action.
     */
    @Composable
    fun Duplicate() {
        Icon(vectorResource(Res.drawable.duplicate))
    }


    /**
     * The icon for a "Delete" action.
     */
    @Composable
    fun Delete(modifier: Modifier = Modifier) {
        Icon(
            imageVector = vectorResource(Res.drawable.delete),
            modifier = modifier
        )
    }


    /**
     * The icon for an "Edit" action.
     */
    @Composable
    fun Edit(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Edit,
            modifier = modifier
        )
    }


    /**
     * The icon for a "Hashtag" action.
     */
    @Composable
    fun Hashtag() {
        Icon(TheorycrafterTheme.iconStyle.Tag)
    }


    /**
     * The icon for a "Share" action.
     */
    @Composable
    fun Share(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.IosShare,
            modifier = modifier
        )
    }


    /**
     * The icon for an "Open in New" action.
     */
    @Composable
    fun OpenInNew() {
        Icon(TheorycrafterTheme.autoMirroredIconStyle.OpenInNew)
    }


    /**
     * The icon for an "Import from file" action.
     */
    @Composable
    fun ImportFromFile() {
        Icon(TheorycrafterTheme.iconStyle.FileOpen)
    }


    /**
     * The icon for an "Import from Pyfa" action.
     */
    @Composable
    fun ImportFromPyfa() {
        SingleLineText(
            text = "Py",
            style = TextStyle(
                fontSize = 13.sp,
                letterSpacing = (-2).sp,
            ),
            textAlign = TextAlign.Center,
            modifier = Modifier
                .defaultMinSize(24.dp)
                .semantics {
                    role = Role.Image
                    set(SemanticsProperties.Text, emptyList())
                }
        )
    }


    /**
     * The icon for a "Plus One" action.
     */
    @Composable
    fun PlusOne() {
        Icon(vectorResource(Res.drawable.plus_one))
    }


    /**
     * The icon for a "Minus One" action.
     */
    @Composable
    fun MinusOne() {
        Icon(vectorResource(Res.drawable.minus_one))
    }


    /**
     * The icon for an "Add to cargo" action.
     */
    @Composable
    fun AddToCargo() {
        Icon(vectorResource(Res.drawable.add_to_cargo))
    }


    /**
     * The icon for a "Pack for battle" action.
     */
    @Composable
    fun PackForBattle() {
        Icon(vectorResource(Res.drawable.pack_for_battle))
    }


    /**
     * The icon for editing an item's mutation.
     */
    @Composable
    fun EditMutation() {
        Icon(TheorycrafterTheme.iconStyle.ModeEdit)
    }


    /**
     * The icon for reverting an item to its base type.
     */
    @Composable
    fun RevertMutation() {
        Icon(TheorycrafterTheme.autoMirroredIconStyle.Undo)
    }


    /**
     * The icon for setting the spoolup cycles of a module.
     */
    @Composable
    fun SpoolupCycles(modifier: Modifier = Modifier) {
        Icon(
            imageVector = vectorResource(Res.drawable.spoolup_cycles),
            modifier = modifier
        )
    }


    /**
     * The icon for setting the adaptation cycles of a module.
     */
    @Composable
    fun AdaptationCycles(modifier: Modifier = Modifier) {
        SpoolupCycles(modifier)
    }


    /**
     * The icon for enabling all items of some kind.
     */
    @Composable
    fun EnableAll() {
        Icon(TheorycrafterTheme.iconStyle.DoneAll)
    }


    /**
     * The icon for disabling all items of some kind.
     */
    @Composable
    fun DisableAll() {
        Icon(TheorycrafterTheme.iconStyle.RemoveDone)
    }


    /**
     * The icon used to indicate the given module state.
     */
    @Composable
    fun ModuleState(
        state: Module.State,
        modifier: Modifier = Modifier
    ){
        when (state){
            Module.State.OFFLINE -> OfflineItem(modifier)
            Module.State.ONLINE -> OnlineItem(modifier)
            Module.State.ACTIVE -> ActiveItem(modifier)
            Module.State.OVERLOADED -> OverloadedItem(modifier)
        }
    }


    /**
     * The icon used to indicate the given drone group state.
     */
    @Composable
    fun DroneGroupState(
        isActive: Boolean,
        modifier: Modifier = Modifier
    ){
        return if (isActive)
            ActiveItem(modifier)
        else
            OnlineItem(modifier)
    }


    /**
     * The icon used to indicate the given enabled state of some item.
     */
    @Composable
    fun ItemEnabledState(
        enabled: Boolean,
        modifier: Modifier = Modifier
    ) {
        return if (enabled)
            ActiveItem(modifier)
        else
            OfflineItem(modifier)
    }


    /**
     * The icon used to indicate an offline item.
     */
    @Composable
    fun OfflineItem(modifier: Modifier = Modifier) {
        ItemStateIconImpl(
            resource = Res.drawable.item_offline,
            contentDescription = "Module is offline",
            color = Color(209, 66, 44),
            modifier = modifier
        )
    }


    /**
     * The icon used to indicate an online item.
     */
    @Composable
    fun OnlineItem(modifier: Modifier = Modifier) {
        ItemStateIconImpl(
            resource = Res.drawable.item_online,
            contentDescription = "Module is online",
            color = Color(180, 170, 80),
            modifier = modifier
        )
    }


    /**
     * The icon used to indicate an active item.
     */
    @Composable
    fun ActiveItem(modifier: Modifier = Modifier) {
        ItemStateIconImpl(
            resource = Res.drawable.item_active,
            contentDescription = "Module is active",
            color = Color(0, 170, 0),
            modifier = modifier
        )
    }


    /**
     * The icon used to indicate an overloaded item.
     */
    @Composable
    fun OverloadedItem(modifier: Modifier = Modifier) {
        ItemStateIconImpl(
            resource = Res.drawable.item_overloaded,
            contentDescription = "Module is overloaded",
            color = Color(219, 115, 76),
            modifier = modifier
        )
    }


    /**
     * The icon indicating some information is available.
     */
    @Composable
    fun Info(
        contentDescription: String? = null,
        fillColor: Color = Color.Unspecified,
        modifier: Modifier = Modifier
    ) {
        Box(
            modifier = modifier
                .semantics(mergeDescendants = true) {
                    if (contentDescription != null) {
                        this.contentDescription = contentDescription
                    }
                    this.role = Role.Image
                },
            propagateMinConstraints = true,
        ) {
            if (fillColor.isSpecified)
                Icon(Icons.Filled.Info, contentDescription = null, tint = fillColor)
            Icon(Icons.Outlined.Info, contentDescription = null)
        }
    }


    /**
     * The icon indicating some information is available.
     *
     * This variant is filled with the base background color.
     */

    /**
     * The icon for showing (Eve) item info.
     */
    @Composable
    fun EveItemInfo(
        contentDescription: String? = null,
        modifier: Modifier = Modifier
    ) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Info,
            contentDescription = contentDescription,
            modifier = modifier
        )
    }


    /**
     * The icon for search fields.
     */
    @Composable
    fun Search(
        contentDescription: String? = null,
        modifier: Modifier = Modifier
    ) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Search,
            contentDescription = contentDescription,
            modifier = modifier
        )
    }


    /**
     * The [ImageVector] for the menu button icon.
     */
    val MenuImageVector: ImageVector = TheorycrafterTheme.iconStyle.Menu


    /**
     * The icon for the settings button.
     */
    @Composable
    fun Settings(
        contentDescription: String? = null,
        modifier: Modifier = Modifier
    ) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Settings,
            contentDescription = contentDescription,
            modifier = modifier
        )
    }


    /**
     * The icon for the market tree button.
     */
    @Composable
    fun Market(
        contentDescription: String? = null,
        modifier: Modifier = Modifier
    ) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Storefront,
            contentDescription = contentDescription,
            modifier = modifier
        )
    }


    /**
     * The icon for the "Graphs" button.
     */
    @Composable
    fun Graphs(
        contentDescription: String? = null,
        modifier: Modifier = Modifier
    ) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.QueryStats,
            contentDescription = contentDescription,
            modifier = modifier
        )
    }


    /**
     * The icon for the "Doctrines" button.
     */
    @Composable
    fun Doctrines(
        contentDescription: String? = null,
        modifier: Modifier = Modifier
    ) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Rocket,
            contentDescription = contentDescription,
            modifier = modifier
        )
    }


    /**
     * The icon used to mark the default skill set.
     */
    @Composable
    fun DefaultSkillSet(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Star,
            contentDescription = null,
            modifier = modifier.height(TheorycrafterTheme.sizes.defaultSkillSetIcon)
        )
    }


    /**
     * The icon for moving something up a row.
     */
    @Composable
    fun MoveUp() {
        Icon(TheorycrafterTheme.iconStyle.MoveUp)
    }


    /**
     * The icon for moving something down a row.
     */
    @Composable
    fun MoveDown() {
        Icon(TheorycrafterTheme.iconStyle.MoveDown)
    }


    /**
     * The icon for adding something.
     */
    @Composable
    fun Add() {
        Icon(TheorycrafterTheme.iconStyle.Add)
    }


    /**
     * The icon for removing something.
     */
    @Composable
    fun Remove() {
        Icon(TheorycrafterTheme.iconStyle.Remove)
    }


    /**
     * The icon for applying all cross-fit friendly effects.
     */
    @Composable
    fun ApplyCrossFitFriendlyEffects() {
        Icon(TheorycrafterTheme.iconStyle.SyncAlt)
    }


    /**
     * The icon for a cancel action.
     */
    @Composable
    fun Cancel(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Cancel,
            modifier = modifier
        )
    }


    /**
     * The icon for a small x.
     */
    @Composable
    fun Close(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Close,
            modifier = modifier
        )
    }


    /**
     * The icon for a grouped/ungrouped state.
     */
    @Composable
    fun Grouped(
        grouped: Boolean,
        modifier: Modifier
    ) {
        Icon(
            imageVector = with(TheorycrafterTheme.iconStyle) {
                if (grouped) Link else LinkOff
            },
            modifier = modifier
        )
    }


    /**
     * A standard expand/collapse icon.
     */
    @Composable
    fun TreeListExpandCollapse(
        expanded: Boolean,
        modifier: Modifier,
    ) {
        Icon(
            modifier = modifier,
            imageVector = if (expanded)
                TheorycrafterTheme.iconStyle.KeyboardArrowDown
            else
                TheorycrafterTheme.autoMirroredIconStyle.KeyboardArrowRight,
            contentDescription = if (expanded) "Expanded" else "Collapsed",
        )
    }


    /**
     * The icon for tournaments.
     */
    @Composable
    fun Tournaments(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.EmojiEvents,
            modifier = modifier
        )
    }


    /**
     * The icon for the prices settings pane.
     */
    @Composable
    fun Prices(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Money,
            contentDescription = "Prices",
            modifier = modifier
        )
    }


    /**
    * The icon for loading charges into modules.
     */
    @Composable
    fun LoadCharges() {
        Icon(TheorycrafterTheme.autoMirroredIconStyle.Input)
    }


    /**
     * The icon for a warning.
     */
    @Composable
    fun Warning(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Warning,
            contentDescription = null,
            tint = TheorycrafterTheme.colors.base().warningContent,
            modifier = modifier
        )
    }


    /**
     * The icon for a green "OK" checkmark.
     */
    @Composable
    fun OkCheckmark(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Check,
            contentDescription = null,
            tint = TheorycrafterTheme.colors.base().successContent,
            modifier = modifier
        )
    }


    /**
     * The icon for the appearance settings.
     */
    @Composable
    fun AppearanceSettings(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Contrast,
            contentDescription = "Appearance",
            modifier = modifier
        )
    }


    /**
     * The icon for the skill set settings.
     */
    @Composable
    fun SkillSetSettings(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Looks5,
            contentDescription = "Skill Sets",
            modifier = modifier
        )
    }


    /**
     * The icon for the tracking consent settings pane.
     */
    @Composable
    fun TrackingConsent(modifier: Modifier = Modifier) {
        Icon(
            imageVector = when (TheorycrafterContext.settings.analytics.consent) {
                AnalyticsConsent.Yes -> TheorycrafterTheme.iconStyle.SentimentSatisfied
                AnalyticsConsent.No -> TheorycrafterTheme.iconStyle.SentimentDissatisfied
                AnalyticsConsent.Undecided -> TheorycrafterTheme.iconStyle.SentimentNeutral
            },
            contentDescription = "Tracking Consent",
            modifier = modifier
        )
    }


    /**
     * The icon for the Theorycrafter updates settings pane.
     */
    @Composable
    fun SoftwareUpdates(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.BrowserUpdated,
            contentDescription = "Updates",
            modifier = modifier
        )
    }


    /**
    * The icon for the "About" settings pane.
     */
    @Composable
    fun AboutSettings(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Copyright,
            contentDescription = "About",
            modifier = modifier
        )
    }


    /**
     * The icon for a push-pin.
     */
    @Composable
    fun PushPin(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.PushPin,
            contentDescription = null,
            modifier = modifier
        )
    }


    /**
     * The icon for adding a tag.
     */
    @Composable
    fun AddTag(modifier: Modifier = Modifier) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.NewLabel,
            contentDescription = "Add tag",
            modifier = modifier
        )
    }


    /**
     * The icon for a fit optimization action.
     */
    @Composable
    fun OptimizeFit() {
        Icon(vectorResource(Res.drawable.optimize))
    }


    /**
     * The icon indicating a ship is a flagship.
     */
    @Composable
    fun Flagship(
        modifier: Modifier = Modifier
    ) {
        Icon(
            imageVector = TheorycrafterTheme.iconStyle.Flag,
            modifier = modifier
        )
    }


}


/**
 * A variant of [Icon] that doesn't require a content description.
 */
@Composable
private fun Icon(
    imageVector: ImageVector,
    modifier: Modifier = Modifier,
) {
    Icon(
        imageVector = imageVector,
        contentDescription = null,
        modifier = modifier
    )
}


/**
 * An icon representing a module or drone state.
 */
@Composable
private fun ItemStateIconImpl(
    resource: DrawableResource,
    contentDescription: String?,
    color: Color,
    modifier: Modifier
) {
    Image(
        imageVector = vectorResource(resource),
        contentDescription = contentDescription,
        colorFilter = ColorFilter.tint(color),
        contentScale = ContentScale.Fit,  // Scale with the size of the module name text
        modifier = modifier
            .size(TheorycrafterTheme.sizes.itemStateIconSize)
    )
}


/**
 * Cache of Eve object loaded bitmap images.
 */
private val eveObjectPainterCache = mutableMapOf<EveObjectWithIcon, Painter?>()


/**
 * Returns a cached painter of the given bitmap resource from the EveData module.
 */
@OptIn(ExperimentalResourceApi::class)
@Composable
fun cachedEveResourcePainter(eveObject: EveObjectWithIcon): Painter? {
    return eveObjectPainterCache.getOrPut(eveObject) {
        runCatching {
            val bytes = eveObject.loadIconBytes() ?: return@runCatching null
            BitmapPainter(bytes.decodeToImageBitmap())
        }.getOrNull()
    }
}


/**
 * Loads and returns the byte array for this item type's icon.
 *
 * @return The byte array for the icon's image, or `null` if this type has no icon.
 * @throws [MissingResourceException] if the icon can't be found.
 */
fun EveObjectWithIcon.loadIconBytes(): ByteArray? {
    val resourcePath = iconResourcePath() ?: return null
    val stream = javaClass.getResourceAsStream(resourcePath) ?:
    throw MissingResourceException("Image for icon of $this not found", javaClass.name, resourcePath)
    return stream.use { it.readBytes() }
}



/**
 * The [ImageVector] used when a resource image is missing.
 */
private val MissingResourceImageVector = TheorycrafterTheme.autoMirroredIconStyle.HelpCenter


/**
 * An [Image] that draws the image loaded from the given EveData resource.
 */
@Composable
private fun EveResourceImage(
    eveObject: EveObjectWithIcon,
    contentDescription: String?,
    modifier: Modifier = Modifier,
    alignment: Alignment = Alignment.Center,
    contentScale: ContentScale = ContentScale.Fit,
    alpha: Float = DefaultAlpha,
    colorFilter: ColorFilter? = null
) {
    val painter = cachedEveResourcePainter(eveObject)
    if (painter != null) {
        Image(
            painter = painter,
            contentDescription = contentDescription,
            modifier = modifier,
            alignment = alignment,
            contentScale = contentScale,
            alpha = alpha,
            colorFilter = colorFilter,
        )
    } else {
        Image(
            imageVector = MissingResourceImageVector,
            contentDescription = contentDescription,
            modifier = modifier,
            alignment = alignment,
            contentScale = contentScale,
            alpha = alpha,
            colorFilter = ColorFilter.tint(LocalContentColor.current.copy(alpha = LocalContentAlpha.current))
        )
    }
}
