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

import androidx.compose.material.Typography
import androidx.compose.runtime.Composable
import androidx.compose.runtime.Stable
import androidx.compose.runtime.remember
import androidx.compose.ui.geometry.Offset
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.graphics.StrokeJoin
import androidx.compose.ui.graphics.drawscope.Fill
import androidx.compose.ui.graphics.drawscope.Stroke
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.TextStyle
import androidx.compose.ui.text.font.FontFamily
import androidx.compose.ui.text.font.FontStyle
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.text.style.TextAlign
import androidx.compose.ui.unit.sp
import com.pixelized.desktop.lwa.ui.theme.color.LwaColors
import com.pixelized.desktop.lwa.ui.theme.typography.LwaTypography.Settings
import com.pixelized.desktop.lwa.ui.theme.typography.fonts.RobotoMono

@Stable
data class LwaTypography(
    val robotoMono: Typography,
    val system: Typography,
    val chat: Chat,
    val settings: Settings,
    val portrait: Portrait,
    val characterSheet: CharacterSheet,
    val inventory: Inventory,
    val freeDiceThrow: Dice,
    val debug: Debug,
) {
    @Stable
    data class Chat(
        val timestamp: TextStyle,
        val text: TextStyle,
    )

    @Stable
    data class Settings(
        val section: TextStyle,
        val title: TextStyle,
        val input: TextStyle,
        val description: TextStyle,
    )

    @Stable
    data class Portrait(
        val value: TextStyle,
        val separator: TextStyle,
        val max: TextStyle,
        val dice: TextStyle,
    )

    @Stable
    data class CharacterSheet(
        val headerValue: TextStyle,
        val headerCaption: TextStyle,
        val characteristic: TextStyle,
        val skill: TextStyle,
    )

    @Stable
    data class Inventory(
        val countOutline: TextStyle,
        val count: TextStyle,
        val label: TextStyle,
    )

    @Stable
    data class Dice(
        val dice: TextStyle,
        val result: TextStyle,
    )

    @Stable
    data class Debug(
        val title: TextStyle,
        val propertyId: TextStyle,
        val propertyIdSpan: SpanStyle,
        val propertyValue: TextStyle,
    )
}

@Composable
@Stable
fun lwaTypography(
    colors: LwaColors,
): LwaTypography {
    val system = Typography()
    val robotoMono = Typography(fontFamily = RobotoMono())

    return remember {
        LwaTypography(
            system = system,
            robotoMono = robotoMono,
            chat = LwaTypography.Chat(
                timestamp = system.body1.copy(
                    fontWeight = FontWeight.Normal,
                    fontSize = 12.sp,
                    lineHeight = 16.sp,
                    letterSpacing = 0.sp,
                    color = colors.chat.timestamp,
                ),
                text = system.body1.copy(
                    fontWeight = FontWeight.Normal,
                    fontSize = 14.sp,
                    lineHeight = 16.sp,
                    letterSpacing = 0.4.sp,
                    color = colors.chat.text,
                ),
            ),
            settings = Settings(
                section = system.h6,
                title = system.body1.copy(
                    fontWeight = FontWeight.SemiBold,
                ),
                input = system.body1.copy(
                    fontWeight = FontWeight.SemiBold,
                    fontSize = 18.sp,
                    lineHeight = 26.sp,
                    textAlign = TextAlign.End,
                ),
                description = system.caption.copy(
                    fontStyle = FontStyle.Italic,
                    color = colors.base.onSurface.copy(alpha = 0.7f),
                ),
            ),
            portrait = LwaTypography.Portrait(
                value = robotoMono.caption.copy(
                    fontWeight = FontWeight.Bold,
                    fontSize = 14.sp,
                    shadow = Shadow(
                        color = Color.Black,
                        offset = Offset(x = 1f, y = 1f),
                        blurRadius = 2f,
                    ),
                ),
                separator = system.caption.copy(
                    fontWeight = FontWeight.ExtraLight,
                    fontSize = 12.sp,
                    shadow = Shadow(
                        color = Color.Black,
                        offset = Offset(x = 1f, y = 1f),
                        blurRadius = 2f,
                    ),
                ),
                max = robotoMono.caption.copy(
                    fontWeight = FontWeight.Light,
                    fontSize = 12.sp,
                    shadow = Shadow(
                        color = Color.Black,
                        offset = Offset(x = 1f, y = 1f),
                        blurRadius = 2f,
                    ),
                ),
                dice = robotoMono.h5.copy(
                    fontWeight = FontWeight.Medium,
                    shadow = Shadow(
                        color = colors.base.surface,
                        offset = Offset.Zero,
                        blurRadius = 8f,
                    )
                )
            ),
            characterSheet = LwaTypography.CharacterSheet(
                headerValue = robotoMono.subtitle1.copy(
                    fontSize = 18.sp,
                    fontWeight = FontWeight.Medium,
                ),
                headerCaption = system.caption,
                characteristic = robotoMono.h3.copy(
                    fontWeight = FontWeight.Normal,
                ),
                skill = robotoMono.subtitle1.copy(
                    fontSize = 16.sp,
                    fontWeight = FontWeight.Medium,
                ),
            ),
            inventory = LwaTypography.Inventory(
                countOutline = robotoMono.caption.copy(
                    fontWeight = FontWeight.Medium,
                    color = colors.elevated.base4dp,
                    drawStyle = Stroke(
                        miter = 3f,
                        width = 3f,
                        join = StrokeJoin.Round,
                    )
                ),
                count = robotoMono.caption.copy(
                    fontWeight = FontWeight.Medium,
                    color = colors.base.onSurface,
                    drawStyle = Fill
                ),
                label = system.body1.copy(
                    fontWeight = FontWeight.Normal,
                ),
            ),
            freeDiceThrow = LwaTypography.Dice(
                dice = robotoMono.h6.copy(
                    color = colors.base.onSurface,
                ),
                result = robotoMono.h4.copy(
                    color = colors.base.onSurface,
                ),
            ),
            debug = LwaTypography.Debug(
                title = robotoMono.caption.copy(
                    fontWeight = FontWeight.Medium,
                    fontSize = 14.sp,
                    lineHeight = 14.sp,
                ),
                propertyId = robotoMono.caption.copy(
                    fontWeight = FontWeight.Normal,
                    fontSize = 10.sp,
                    lineHeight = 14.sp,
                ),
                propertyIdSpan = robotoMono.caption.copy(
                    fontWeight = FontWeight.Normal,
                    fontSize = 10.sp,
                    lineHeight = 14.sp,
                ).toSpanStyle(),
                propertyValue = robotoMono.caption.copy(
                    fontWeight = FontWeight.Normal,
                    fontSize = 12.sp,
                    lineHeight = 14.sp,
                ),
            ),
        )
    }
}

@Stable
fun Typography(fontFamily: FontFamily): Typography = Typography().let { typography: Typography ->
    typography.copy(
        h1 = typography.h1.copy(fontFamily = fontFamily),
        h2 = typography.h2.copy(fontFamily = fontFamily),
        h3 = typography.h3.copy(fontFamily = fontFamily),
        h4 = typography.h4.copy(fontFamily = fontFamily),
        h5 = typography.h5.copy(fontFamily = fontFamily),
        h6 = typography.h6.copy(fontFamily = fontFamily),
        subtitle1 = typography.subtitle1.copy(fontFamily = fontFamily),
        subtitle2 = typography.subtitle2.copy(fontFamily = fontFamily),
        body1 = typography.body1.copy(fontFamily = fontFamily),
        body2 = typography.body2.copy(fontFamily = fontFamily),
        button = typography.button.copy(fontFamily = fontFamily),
        caption = typography.caption.copy(fontFamily = fontFamily),
        overline = typography.overline.copy(fontFamily = fontFamily),
    )
}