package wang.yaojia.webterm.components

import androidx.compose.foundation.horizontalScroll
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.rememberScrollState
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import wang.yaojia.webterm.designsystem.Spacing
import wang.yaojia.webterm.designsystem.TelemetryChip
import wang.yaojia.webterm.designsystem.WebTermTheme
import wang.yaojia.webterm.wire.PrInfo
import wang.yaojia.webterm.wire.RateInfo
import wang.yaojia.webterm.wire.StatusTelemetry
import wang.yaojia.webterm.wire.Tunables
import java.util.Locale
import kotlin.math.roundToInt

/**
 * # TelemetryChips (A22) — the statusLine telemetry chip row.
 *
 * A horizontally-scrollable row of A13 [TelemetryChip] primitives — context %, $cost, model, PR,
 * rate — derived from the latest [StatusTelemetry] frame (plan §1). Every chip **greys out together**
 * when the frame is stale (its [at][StatusTelemetry.at] older than
 * [TELEMETRY_STALE_TTL_MS][Tunables.TELEMETRY_STALE_TTL_MS]); a chip switches to the amber warning
 * color when its metric crosses a threshold (near-full context, near-limit rate, PR changes-requested).
 *
 * Chip text is inert monospaced [TelemetryChip] output (no linkify, §8). The model string is
 * server-controlled but renders as a plain chip label. Layout is device-QA; the staleness rule and
 * chip derivation are the JVM-tested core ([isTelemetryStale] / [telemetryChipModels]).
 *
 * @param nowMs current wall clock (ms since epoch); the screen re-supplies it on a tick so chips grey
 *   as the frame ages.
 */
@Composable
public fun TelemetryChips(
    telemetry: StatusTelemetry,
    nowMs: Long,
    modifier: Modifier = Modifier,
) {
    val stale = isTelemetryStale(telemetry.at, nowMs)
    val models = telemetryChipModels(telemetry)
    Row(
        modifier = modifier.horizontalScroll(rememberScrollState()),
        horizontalArrangement = Arrangement.spacedBy(Spacing.xs4),
    ) {
        for (model in models) {
            TelemetryChip(text = model.text, isStale = stale, isWarning = model.isWarning)
        }
    }
}

/** One derived chip: pre-formatted [text] plus whether it crossed a warning threshold. */
public data class TelemetryChipModel(val text: String, val isWarning: Boolean = false)

/** Context %, 5-hour and 7-day rate at/above which a chip turns amber (mirrors the web statusline). */
private const val CONTEXT_WARN_PCT: Double = 90.0
private const val RATE_WARN_PCT: Double = 90.0
private const val REVIEW_CHANGES_REQUESTED: String = "CHANGES_REQUESTED"

/**
 * True iff [telemetry.at][StatusTelemetry.at] (server receive time) is older than the stale TTL as of
 * [nowMs]. Boundary: exactly-TTL-old is NOT yet stale ("older than", [Tunables.TELEMETRY_STALE_TTL_MS]).
 * Pure — the JVM-tested staleness threshold.
 */
public fun isTelemetryStale(atMs: Long, nowMs: Long): Boolean =
    nowMs - atMs > Tunables.TELEMETRY_STALE_TTL_MS

/**
 * Derive the ordered chip list from a telemetry frame, skipping absent metrics. Pure + deterministic
 * so the formatting + warning thresholds are unit-tested without Compose. Order mirrors the web
 * statusLine: context · cost · model · PR · rate.
 */
public fun telemetryChipModels(telemetry: StatusTelemetry): List<TelemetryChipModel> {
    val chips = mutableListOf<TelemetryChipModel>()
    telemetry.contextUsedPct?.let {
        chips += TelemetryChipModel("ctx ${it.roundToInt()}%", isWarning = it >= CONTEXT_WARN_PCT)
    }
    telemetry.costUsd?.let {
        chips += TelemetryChipModel(String.format(Locale.US, "$%.2f", it))
    }
    telemetry.model?.takeIf { it.isNotBlank() }?.let {
        chips += TelemetryChipModel(it)
    }
    telemetry.pr?.let { chips += prChip(it) }
    telemetry.rate?.fiveHourPct?.let {
        chips += TelemetryChipModel("5h ${it.roundToInt()}%", isWarning = it >= RATE_WARN_PCT)
    }
    return chips
}

private fun prChip(pr: PrInfo): TelemetryChipModel =
    TelemetryChipModel("PR #${pr.number}", isWarning = pr.reviewState == REVIEW_CHANGES_REQUESTED)

// ── Preview ─────────────────────────────────────────────────────────────────────

@Preview(name = "TelemetryChips")
@Composable
private fun TelemetryChipsPreview() {
    WebTermTheme {
        TelemetryChips(
            telemetry = StatusTelemetry(
                contextUsedPct = 92.0,
                costUsd = 0.1234,
                model = "opus-4.8",
                pr = PrInfo(number = 7, url = "", reviewState = REVIEW_CHANGES_REQUESTED),
                rate = RateInfo(fiveHourPct = 40.0),
                at = 0L,
            ),
            nowMs = 0L,
        )
    }
}
