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

import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.ColumnScope
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.Card
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.unit.dp
import com.runicgateway.app.ui.theme.LocalShardPalette
import com.runicgateway.app.ui.theme.LocalShardStructure
import com.runicgateway.app.ui.theme.ShardDanger
import com.runicgateway.app.ui.theme.ShardDangerBg
import com.runicgateway.app.ui.theme.ShardSuccess
import com.runicgateway.app.ui.theme.ShardSuccessBg
import com.runicgateway.app.ui.theme.ShardSuccessDot
import com.runicgateway.app.ui.theme.ShardWarning
import com.runicgateway.app.ui.theme.ShardWarningBg

/**
 * Shared visual building blocks for the M5 shard-website design pass
 * (docs/android/PLAN.md §M5): the recurring pill, section-label, feature-card,
 * and stat-bar motifs the mockup repeats across screens. Pure presentation —
 * no state, no data dependencies — so any screen can adopt them.
 *
 * This is the app's **only** file that reaches past `MaterialTheme` for a
 * themable value, so it is the one place M12 had to migrate: the surface, line
 * and accent tokens come from [LocalShardPalette] and the pill shape and card
 * depth from [LocalShardStructure], both following the shard's theme
 * (THEMING_AND_NAV.md §5.1, §5.2, §5.4). The success/warning/danger constants
 * stay imported directly — those are semantic and never themed, mirroring the
 * server's `FIXED_TOKENS`.
 */

/** Semantic tone for a [StatusPill] / [OnlineDot]. */
enum class PillTone { Success, Warning, Danger, Neutral, Info }

private data class PillColors(val fg: Color, val bg: Color)

@Composable
private fun toneColors(tone: PillTone): PillColors = when (tone) {
    PillTone.Success -> PillColors(ShardSuccess, ShardSuccessBg)
    PillTone.Warning -> PillColors(ShardWarning, ShardWarningBg)
    PillTone.Danger -> PillColors(ShardDanger, ShardDangerBg)
    PillTone.Neutral, PillTone.Info ->
        LocalShardPalette.current.let { PillColors(it.pillFg, it.pillBg) }
}

/**
 * A small uppercase status chip — "Live", "Up", "Enabled", "IDOC", a role — with a
 * rounded filled background tinted by [tone]. Mirrors the mockup's pill badges.
 *
 * The one place `--radius-pill` lands: the app's other two [CircleShape] uses are
 * 8dp status dots, and a dot stays a dot however square the shard makes its site.
 */
@Composable
fun StatusPill(text: String, tone: PillTone, modifier: Modifier = Modifier) {
    val c = toneColors(tone)
    Surface(color = c.bg, shape = LocalShardStructure.current.pill, modifier = modifier) {
        Text(
            text = text.uppercase(),
            style = MaterialTheme.typography.labelSmall,
            color = c.fg,
            modifier = Modifier.padding(horizontal = 10.dp, vertical = 4.dp),
        )
    }
}

/** The small colored status dot (green when live), matched to a [PillTone]. */
@Composable
fun OnlineDot(tone: PillTone, modifier: Modifier = Modifier) {
    val color = when (tone) {
        PillTone.Success -> ShardSuccessDot
        PillTone.Warning -> ShardWarning
        PillTone.Danger -> ShardDanger
        PillTone.Neutral, PillTone.Info -> LocalShardPalette.current.faint
    }
    Box(modifier.size(8.dp).clip(CircleShape).background(color))
}

/**
 * The muted, uppercase, letter-spaced section header the design uses above grouped
 * content ("Attributes", "Vitals", "Password", "Linked accounts").
 */
@Composable
fun SectionLabel(text: String, modifier: Modifier = Modifier) {
    Text(
        text = text.uppercase(),
        style = MaterialTheme.typography.labelSmall,
        color = LocalShardPalette.current.faint,
        modifier = modifier,
    )
}

/**
 * The elevated "feature" card: a vertical blue gradient with a hairline outline and
 * soft shadow, used for the home status card, the shard-online banner, and the
 * vendor card. [content] is laid out in a padded [Column].
 *
 * The radius is `MaterialTheme.shapes.medium` rather than the literal 12dp it was
 * built with — the same value, now following `--radius-card`'s ratio (§5.2). The
 * shadow this doc always claimed is finally drawn, at the depth `--shadow-card`
 * resolves to (§5.4).
 */
@Composable
fun FeatureCard(
    modifier: Modifier = Modifier,
    contentPadding: Int = 18,
    content: @Composable ColumnScope.() -> Unit,
) {
    val palette = LocalShardPalette.current
    val shape = MaterialTheme.shapes.medium
    Box(
        modifier = modifier
            .fillMaxWidth()
            .shadow(LocalShardStructure.current.cardElevation, shape)
            .clip(shape)
            .background(Brush.verticalGradient(listOf(palette.cardTop, palette.cardBottom)))
            .border(1.dp, palette.outline, shape),
    ) {
        Column(Modifier.padding(contentPadding.dp), content = content)
    }
}

/**
 * A Material [Card] at the shard's resolved depth — the app's standard card, and
 * the reason every screen's `Card(` became a `ShardCard(`.
 *
 * `Card` takes its elevation as a **default argument**, not from the theme, so
 * unlike the color scheme and the shape scale there is no way to make
 * `--shadow-card` reach ~24 call sites without a wrapper. Passing
 * [CardDefaults.cardElevation] at each site instead would have put the same line
 * in eighteen files and let one drift. A `Card(` outside this file is therefore a
 * card the shard cannot theme, which makes the invariant greppable.
 */
@Composable
fun ShardCard(modifier: Modifier = Modifier, content: @Composable ColumnScope.() -> Unit) {
    Card(
        modifier = modifier,
        elevation = CardDefaults.cardElevation(defaultElevation = LocalShardStructure.current.cardElevation),
        content = content,
    )
}

/**
 * A slim rounded meter (vitals / skills). [fraction] is clamped to 0..1; the fill is
 * the slate accent over a bordered dark track.
 */
@Composable
fun StatBar(fraction: Float, modifier: Modifier = Modifier) {
    val pct = fraction.coerceIn(0f, 1f)
    val palette = LocalShardPalette.current
    Box(
        modifier = modifier
            .fillMaxWidth()
            .height(6.dp)
            .clip(RoundedCornerShape(3.dp))
            .background(palette.elevated)
            .border(1.dp, palette.outline, RoundedCornerShape(3.dp)),
    ) {
        Box(
            Modifier
                .fillMaxWidth(pct)
                .height(6.dp)
                .clip(RoundedCornerShape(3.dp))
                .background(MaterialTheme.colorScheme.secondary),
        )
    }
}
