package com.pixelized.desktop.lwa.ui.theme.color

import androidx.compose.material.Colors
import androidx.compose.material.darkColors
import androidx.compose.runtime.Composable
import androidx.compose.runtime.ReadOnlyComposable
import androidx.compose.runtime.Stable
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.compositeOver
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp
import kotlin.math.ln

@Stable
data class LwaColors(
    val base: Colors,
    val elevated: Elevated,
    val portrait: Portrait,
    val portraitBackgroundBrush: Brush,
    val chat: Chat,
) {
    @Stable
    data class Elevated(
        val base1dp: Color,
        val base2dp: Color,
        val base3dp: Color,
        val base4dp: Color,
    )

    @Stable
    data class Portrait(
        val levelUp: Color,
        val blood: Color,
        val criticalSuccess: Color,
        val spacialSuccess: Color,
        val success: Color,
        val failure: Color,
        val criticalFailure: Color,
        val default: Color,
    )

    @Stable
    data class Chat(
        val timestamp: Color,
        val text: Color,
        val criticalSuccess: Color,
        val spacialSuccess: Color,
        val success: Color,
        val failure: Color,
        val criticalFailure: Color,
    )
}

@Composable
@Stable
fun darkLwaColorTheme(
    base: Colors = darkColors(
        primary = Color(0xFFBB86FC),
        primaryVariant = Color(0xB2BB86FC),
    ),
    elevated: LwaColors.Elevated = LwaColors.Elevated(
        base1dp = base.calculateElevatedColor(
            color = base.surface,
            onColor = base.onSurface,
            elevation = 1.dp,
        ),
        base2dp = base.calculateElevatedColor(
            color = base.surface,
            onColor = base.onSurface,
            elevation = 2.dp,
        ),
        base3dp = base.calculateElevatedColor(
            color = base.surface,
            onColor = base.onSurface,
            elevation = 3.dp,
        ),
        base4dp = base.calculateElevatedColor(
            color = base.surface,
            onColor = base.onSurface,
            elevation = 4.dp,
        ),
    ),
    portraitBackgroundBrush: Brush = Brush.verticalGradient(
        listOf(
            elevated.base1dp.copy(alpha = 0.0f),
            elevated.base1dp.copy(alpha = 0.0f),
            elevated.base1dp.copy(alpha = 0.0f),
            elevated.base1dp.copy(alpha = 0.5f),
            elevated.base1dp.copy(alpha = 0.8f),
        )
    ),
    portrait: LwaColors.Portrait = LwaColors.Portrait(
        levelUp = LwaColorPalette.Gold,
        blood = LwaColorPalette.Blood,
        criticalSuccess = LwaColorPalette.Teal400,
        spacialSuccess = LwaColorPalette.Green400,
        success = LwaColorPalette.LightGreen400,
        failure = LwaColorPalette.Orange400,
        criticalFailure = LwaColorPalette.Red400,
        default = base.primary,
    ),
    chat: LwaColors.Chat = LwaColors.Chat(
        timestamp = base.secondary,
        text = base.onSurface.copy(alpha = 0.7f),
        criticalSuccess = portrait.criticalSuccess,
        spacialSuccess = portrait.spacialSuccess,
        success = portrait.success,
        failure = portrait.failure,
        criticalFailure = portrait.criticalFailure,
    ),
): LwaColors = LwaColors(
    base = base,
    elevated = elevated,
    portrait = portrait,
    portraitBackgroundBrush = portraitBackgroundBrush,
    chat = chat,
)

@ReadOnlyComposable
@Composable
private fun Colors.calculateElevatedColor(color: Color, onColor: Color, elevation: Dp): Color {
    return if (elevation > 0.dp && !isLight) {
        val foregroundColor = calculateForegroundColor(onColor, elevation)
        foregroundColor.compositeOver(color)
    } else {
        color
    }
}

@ReadOnlyComposable
@Composable
private fun calculateForegroundColor(color: Color, elevation: Dp): Color {
    val alpha = ((4.5f * ln(elevation.value + 1)) + 2f) / 100f
    return color.copy(alpha = alpha)
}