package pro.theorycrafter.android

import androidx.compose.foundation.Image
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.ColorFilter
import androidx.compose.ui.graphics.DefaultAlpha
import androidx.compose.ui.graphics.decodeToImageBitmap
import androidx.compose.ui.graphics.painter.BitmapPainter
import androidx.compose.ui.graphics.painter.Painter
import androidx.compose.ui.layout.ContentScale
import eve.data.EveItemType
import eve.data.EveObjectWithIcon
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
            )
        }
    }

}


/**
 * 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.
 */
@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() }
}



/**
 * 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,
        )
    }
}
