import SwiftUI
import WireProtocol

/// # Primitives — reusable SwiftUI building blocks (FROZEN public surface)
///
/// The four component groups compose these by exact name. Each pulls ALL of its
/// constants from `DS`/`StatusStyle`/`DS.Typography` — no inline magic. Every
/// primitive ships a `#Preview`.

// MARK: - StatusBadge

/// Color + distinct SF Symbol (+ optional Chinese label) for one status. The
/// VoiceOver label is baked in from `StatusStyle`, so status is conveyed by
/// shape, color AND speech. The symbol scales with Dynamic Type.
struct StatusBadge: View {
    let status: DisplayStatus
    /// Show the Chinese word next to the symbol (list rows usually don't).
    var showsLabel: Bool = false

    /// Convenience init from the wire enum.
    init(status: DisplayStatus, showsLabel: Bool = false) {
        self.status = status
        self.showsLabel = showsLabel
    }

    init(claude: ClaudeStatus, showsLabel: Bool = false) {
        self.init(status: DisplayStatus(claude), showsLabel: showsLabel)
    }

    private var style: StatusStyle { StatusStyle.style(for: status) }

    var body: some View {
        HStack(spacing: DS.Space.xs4) {
            Image(systemName: style.symbolName)
                .foregroundStyle(style.color)
                .imageScale(.medium)
            if showsLabel {
                Text(style.label)
                    .font(DS.Typography.caption)
                    .foregroundStyle(DS.Palette.textSecondary)
            }
        }
        .accessibilityElement(children: .ignore)
        .accessibilityLabel(style.label)
    }
}

// MARK: - TelemetryChip

/// One pill of monospaced-tabular telemetry (context %, $cost, model, PR…).
/// Greys out + desaturates when `isStale`; a `isWarning` chip switches to the
/// waiting/amber semantic color for over-threshold context.
struct TelemetryChip: View {
    /// Optional leading SF Symbol.
    var systemImage: String? = nil
    let text: String
    var isStale: Bool = false
    var isWarning: Bool = false

    var body: some View {
        HStack(spacing: DS.Space.xs2) {
            if let systemImage {
                Image(systemName: systemImage)
            }
            Text(text)
        }
        .font(DS.Typography.mono(.caption2))
        .lineLimit(1)
        .foregroundStyle(isWarning ? DS.Palette.statusWaiting : DS.Palette.textSecondary)
        .padding(.horizontal, DS.Space.sm8)
        .padding(.vertical, DS.Space.xs2)
        .background(.quaternary, in: Capsule())
        .opacity(isStale ? DS.Opacity.stale : 1)
        .grayscale(isStale ? 1 : 0)
    }
}

// MARK: - Card

/// Standard card container: card surface + hairline stroke + `md12` radius +
/// standard padding. The uniform card spec for rows, grid cells and panels.
struct Card<Content: View>: View {
    /// Inner padding (defaults to `md12`; pass `sm8` for tight rows).
    var padding: CGFloat = DS.Space.md12
    @ViewBuilder var content: () -> Content

    init(padding: CGFloat = DS.Space.md12, @ViewBuilder content: @escaping () -> Content) {
        self.padding = padding
        self.content = content
    }

    var body: some View {
        content()
            .padding(padding)
            .background(DS.Palette.card, in: RoundedRectangle(cornerRadius: DS.Radius.md12))
            .overlay(
                RoundedRectangle(cornerRadius: DS.Radius.md12)
                    .strokeBorder(DS.Palette.hairline, lineWidth: DS.Stroke.hairline)
            )
    }
}

// MARK: - SectionHeader

/// A small, secondary section label (Chinese copy passed verbatim by callers).
struct SectionHeader: View {
    let title: String

    var body: some View {
        Text(title)
            .font(DS.Typography.caption)
            .foregroundStyle(DS.Palette.textSecondary)
    }
}

// MARK: - DSButtonStyle

/// The App's button style. `primary` = accent-filled, `secondary` = tinted
/// outline, `destructive` = red-filled. Always ≥ `minHitTarget` tall, full
/// width, `md12` radius. Press feedback honors Reduce Motion.
struct DSButtonStyle: ButtonStyle {
    enum Kind { case primary, secondary, destructive }
    var kind: Kind = .primary

    func makeBody(configuration: Configuration) -> some View {
        DSButtonBody(kind: kind, configuration: configuration)
    }

    /// Nested view so we can read `@Environment` (a `ButtonStyle` cannot).
    /// Must be as accessible as `DSButtonStyle` (opaque `makeBody` requirement).
    struct DSButtonBody: View {
        let kind: Kind
        let configuration: Configuration
        @Environment(\.accessibilityReduceMotion) private var reduceMotion
        @Environment(\.isEnabled) private var isEnabled

        var body: some View {
            configuration.label
                .font(DS.Typography.body.weight(.semibold))
                .frame(maxWidth: .infinity, minHeight: DS.Layout.minHitTarget)
                .foregroundStyle(foreground)
                .background(background, in: RoundedRectangle(cornerRadius: DS.Radius.md12))
                .overlay(border)
                .opacity(opacity)
                .animation(
                    DS.Motion.gated(DS.Motion.fast, reduceMotion: reduceMotion),
                    value: configuration.isPressed
                )
        }

        private var foreground: Color {
            switch kind {
            // Gold accent fill needs DARK ink for contrast (mirrors web
            // --on-accent), NOT white. Red destructive fill keeps white.
            case .primary: return DS.Palette.onAccent
            case .destructive: return .white
            case .secondary: return DS.Palette.accent
            }
        }

        private var background: Color {
            switch kind {
            case .primary: return DS.Palette.accent
            case .destructive: return DS.Palette.statusStuck
            case .secondary: return DS.Palette.card
            }
        }

        @ViewBuilder private var border: some View {
            if kind == .secondary {
                RoundedRectangle(cornerRadius: DS.Radius.md12)
                    .strokeBorder(DS.Palette.accent, lineWidth: DS.Stroke.hairline)
            }
        }

        private var opacity: Double {
            if !isEnabled { return DS.Opacity.pressed }
            return configuration.isPressed ? DS.Opacity.pressed : 1
        }
    }
}

// MARK: - Previews

#Preview("StatusBadge") {
    VStack(alignment: .leading, spacing: DS.Space.md12) {
        ForEach(DisplayStatus.allCases, id: \.self) { status in
            StatusBadge(status: status, showsLabel: true)
        }
    }
    .padding(DS.Space.lg16)
}

#Preview("TelemetryChip") {
    HStack(spacing: DS.Space.sm8) {
        TelemetryChip(text: "ctx 92%", isWarning: true)
        TelemetryChip(text: "$0.1234")
        TelemetryChip(systemImage: "cpu", text: "opus")
        TelemetryChip(text: "PR #7", isStale: true)
    }
    .padding(DS.Space.lg16)
}

#Preview("Card") {
    Card {
        VStack(alignment: .leading, spacing: DS.Space.sm8) {
            SectionHeader(title: "会话")
            Text(verbatim: "web-terminal")
                .font(DS.Typography.headline)
            Text(verbatim: "2 台设备在看 · 161×50")
                .dsMetaText()
        }
    }
    .padding(DS.Space.lg16)
}

#Preview("DSButtonStyle") {
    VStack(spacing: DS.Space.md12) {
        Button("新建会话") {}.buttonStyle(DSButtonStyle(kind: .primary))
        Button("继续上次会话") {}.buttonStyle(DSButtonStyle(kind: .secondary))
        Button("结束会话") {}.buttonStyle(DSButtonStyle(kind: .destructive))
    }
    .tint(DS.Palette.accent)
    .padding(DS.Space.lg16)
}
