package wang.yaojia.webterm.components

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.RectangleShape
import androidx.compose.ui.graphics.Shape
import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.Preview
import wang.yaojia.webterm.designsystem.Radius
import wang.yaojia.webterm.designsystem.Spacing
import wang.yaojia.webterm.designsystem.WebTermTheme
import wang.yaojia.webterm.designsystem.WebTermType

/**
 * # ContinueLastBanner (A29) — the "继续上次会话" re-entry affordance.
 *
 * The visible half of the continue-last-session cold-start UX (plan §1, §5 A29). When a host still has a
 * live last session ([LastSessionStore][wang.yaojia.webterm.hostregistry.LastSessionStore], kept current
 * by [SessionActivityBridge][wang.yaojia.webterm.wiring.SessionActivityBridge]), this banner is layered
 * on top of the sessions landing; tapping it re-opens THAT session (full scrollback replay) instead of
 * spawning a new one. It renders in two layouts:
 *  - [ContinueLastVariant.Stack] — a full-width strip pinned above a stacked (phone) session list;
 *  - [ContinueLastVariant.Sidebar] — a compact rounded card for the tablet nav sidebar.
 *
 * ### Shown IFF a last session exists
 * The pure [continueLastModel] maps the persisted last-session id to a [ContinueLastModel] (or `null`),
 * and the composable renders NOTHING for a `null` model — so "shown iff a last session exists" is the
 * single JVM-tested rule, no device needed. Layout/gesture polish is device-QA (plan §7).
 *
 * ### Inert rendering (plan §8)
 * The session id is a SERVER-issued (untrusted) string; it is shown as a plain, inert [Text] — no
 * Markdown / autolink / `AnnotatedString` linkify.
 */

/** Which layout the banner renders in — a top strip (phone) or a sidebar card (tablet). */
public enum class ContinueLastVariant { Stack, Sidebar }

/** The banner's derived state: the last session that can be re-opened. */
public data class ContinueLastModel(val sessionId: String)

/**
 * PURE derivation: a non-blank persisted [lastSessionId] yields a [ContinueLastModel] (banner shown);
 * `null`/blank yields `null` (banner hidden). Blank is treated as absent so a corrupt persisted value
 * never renders an un-openable banner.
 */
public fun continueLastModel(lastSessionId: String?): ContinueLastModel? =
    lastSessionId?.takeIf { it.isNotBlank() }?.let { ContinueLastModel(it) }

/**
 * The banner. Renders NOTHING when [model] is `null` (no last session). Tapping the whole surface fires
 * [onContinue] with the session id to re-open. [variant] picks the stack vs sidebar layout.
 */
@Composable
public fun ContinueLastBanner(
    model: ContinueLastModel?,
    onContinue: (String) -> Unit,
    modifier: Modifier = Modifier,
    variant: ContinueLastVariant = ContinueLastVariant.Stack,
) {
    if (model == null) return

    val shape: Shape = when (variant) {
        ContinueLastVariant.Stack -> RectangleShape
        ContinueLastVariant.Sidebar -> RoundedCornerShape(Radius.md12)
    }
    val widthModifier =
        if (variant == ContinueLastVariant.Stack) Modifier.fillMaxWidth() else Modifier

    Surface(
        color = MaterialTheme.colorScheme.primaryContainer,
        contentColor = MaterialTheme.colorScheme.onPrimaryContainer,
        shape = shape,
        modifier = modifier
            .then(widthModifier)
            .clickable { onContinue(model.sessionId) },
    ) {
        Row(
            verticalAlignment = Alignment.CenterVertically,
            horizontalArrangement = Arrangement.spacedBy(Spacing.sm8),
            modifier = Modifier
                .fillMaxWidth()
                .padding(horizontal = Spacing.md12, vertical = Spacing.sm8),
        ) {
            Text(text = "↻", style = MaterialTheme.typography.titleMedium)
            Column(
                modifier = Modifier.weight(1f),
                verticalArrangement = Arrangement.spacedBy(Spacing.xs2),
            ) {
                Text(text = "继续上次会话", style = MaterialTheme.typography.bodyMedium)
                // Untrusted server-issued id — inert Text, no autolink/markdown (§8).
                Text(
                    text = shortSessionId(model.sessionId),
                    style = WebTermType.metaMono,
                    maxLines = 1,
                    overflow = TextOverflow.Ellipsis,
                )
            }
            Text(text = "›", style = MaterialTheme.typography.titleMedium)
        }
    }
}

/** A short, inert label for the (untrusted) session id — the first id segment, capped so it never wraps. */
private fun shortSessionId(sessionId: String): String =
    sessionId.substringBefore('-').take(SHORT_ID_MAX)

private const val SHORT_ID_MAX: Int = 12

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

@Preview(name = "ContinueLastBanner — stack")
@Composable
private fun ContinueLastBannerStackPreview() {
    WebTermTheme {
        ContinueLastBanner(
            model = ContinueLastModel("a1b2c3d4-5678-4abc-9def-000000000000"),
            onContinue = {},
            variant = ContinueLastVariant.Stack,
        )
    }
}

@Preview(name = "ContinueLastBanner — sidebar", widthDp = 220)
@Composable
private fun ContinueLastBannerSidebarPreview() {
    WebTermTheme {
        ContinueLastBanner(
            model = ContinueLastModel("a1b2c3d4-5678-4abc-9def-000000000000"),
            onContinue = {},
            variant = ContinueLastVariant.Sidebar,
            modifier = Modifier.padding(Spacing.md12),
        )
    }
}
