/*
 * SPDX-License-Identifier: GPL-3.0-or-later
 */
package com.runicgateway.app.ui.theme

import androidx.compose.material3.ColorScheme
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.darkColorScheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.CompositionLocalProvider
import androidx.compose.runtime.remember
import com.runicgateway.app.data.appearance.SiteAppearance

/**
 * Maps a resolved [ShardPalette] onto the Material roles (THEMING_AND_NAV.md
 * §5.1). The app is **dark-only** — the design is a single deep blue-black
 * theme, so there is no light variant and the system light/dark setting is
 * intentionally ignored; every v1 preset on the website is dark too.
 *
 * Ten of the palette's fifteen tokens land here, which is why the ~20
 * token-based screens take on a shard's theme with no per-screen color work.
 * Pure, so the no-op proof (AC-1) can assert on it directly.
 */
internal fun shardColorScheme(palette: ShardPalette): ColorScheme = darkColorScheme(
    primary = palette.cta,                 // filled CTA buttons
    onPrimary = palette.onCta,
    secondary = palette.accent,            // links / secondary highlights
    onSecondary = palette.onCta,
    tertiary = palette.accent,
    onTertiary = palette.onCta,
    background = palette.page,
    onBackground = palette.body,
    surface = palette.surface,
    onSurface = palette.body,
    surfaceVariant = palette.elevated,
    onSurfaceVariant = palette.muted,
    surfaceContainer = palette.elevated,
    surfaceContainerHigh = palette.elevated,
    // Material's filled Card takes its container from surfaceContainerHighest —
    // FilledCardTokens.ContainerColor, checked in the 1.3.0 artifact's bytecode.
    // Leaving it unmapped is what made every ShardCard draw in darkColorScheme()'s
    // default grey instead of --panel-flat, on themed AND untouched instances alike
    // (found on device in phase 8's AC-5 walk; see "Phase 8 as landed").
    surfaceContainerHighest = palette.elevated,
    surfaceContainerLow = palette.surface,
    surfaceContainerLowest = palette.surface,
    outline = palette.outline,
    outlineVariant = palette.divider,
    secondaryContainer = palette.pillBg,   // neutral chips / selected drawer item
    onSecondaryContainer = palette.pillFg,
    // Semantic, never themed — mirrors the server's FIXED_TOKENS (§4).
    error = ShardDanger,
    onError = palette.onCta,
    errorContainer = ShardDangerBg,
    onErrorContainer = ShardDanger,
)

/**
 * App theme, themed by the shard (M12). [appearance] carries the resolved token
 * map the admin's Appearance page publishes; it is applied field by field over
 * the shipped palette and shape scale, so [SiteAppearance.NONE] — no settings
 * rows, a backend that predates the feature, or a settings call that failed —
 * renders as the app did before this milestone (§2), the one exception being the
 * card depth [ShardStructure] documents.
 *
 * The palette reaches screens two ways: through [MaterialTheme]'s color scheme
 * for the ten tokens with a Material role, and through [LocalShardPalette] for
 * the five without one. The radii split the same way — [MaterialTheme]'s shape
 * scale for everything Material draws, [LocalShardStructure] for the pill and
 * the card depth, which it cannot carry. The type families need no split and so
 * no composition local: every text style in the app comes from
 * [MaterialTheme.typography], and the two that override anything override the
 * style rather than the family.
 */
@Composable
fun RunicGatewayTheme(
    appearance: SiteAppearance = SiteAppearance.NONE,
    content: @Composable () -> Unit,
) {
    val palette = remember(appearance) {
        ShardPalette.resolve(
            theme = appearance.theme,
            brandAccent = parseBrandColor(appearance.brand?.accent),
        )
    }
    val colorScheme = remember(palette) { shardColorScheme(palette) }
    val structure = remember(appearance) { ShardStructure.resolve(appearance.theme) }
    val typeface = remember(appearance) { ShardTypeface.resolve(appearance.theme) }
    val typography = remember(typeface) { shardTypography(typeface) }

    CompositionLocalProvider(
        LocalShardPalette provides palette,
        LocalShardStructure provides structure,
    ) {
        MaterialTheme(
            colorScheme = colorScheme,
            typography = typography,
            shapes = structure.shapes,
            content = content,
        )
    }
}
