import SwiftUI

/// Design-system primitives  documents/design-system.md.
///
/// Build screens from these, not from ad-hoc stacks. Two rules they enforce:
///  - buttons are always pill-shaped
///  - tinted things go through the 14%/24% formula, and the label stays `Color.muted`
///
/// Swift gotcha: custom `Color` statics don't resolve through leading-dot in generic
/// `ShapeStyle` params  write `Color.brandInk`, not `.brandInk`.

// MARK: - Buttons

/// The ONE primary action on a screen. A second one is a design bug.
struct BrandButton: View {
    let title: String
    var loading: Bool = false
    var enabled: Bool = true
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            ZStack {
                if loading {
                    ProgressView().tint(.brandInk)
                } else {
                    Text(title).fontWeight(.bold)
                }
            }
            .frame(maxWidth: .infinity, minHeight: 56)
        }
        .background(Color.brand, in: Capsule())
        .foregroundStyle(Color.brandInk)
        .disabled(!enabled || loading)
        .opacity(enabled && !loading ? 1 : 0.5)
        .beebGlow()
    }
}

struct SecondaryButton: View {
    let title: String
    var enabled: Bool = true
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            Text(title).fontWeight(.semibold)
                .frame(maxWidth: .infinity, minHeight: 56)
        }
        .background(Color.surfaceRaised, in: Capsule())
        .overlay(Capsule().strokeBorder(Color.lineStrong, lineWidth: 1))
        .foregroundStyle(Color.appForeground)
        .disabled(!enabled)
        .opacity(enabled ? 1 : 0.5)
    }
}

/// Destructive action  tinted, never a filled red block.
struct DangerButton: View {
    let title: String
    var loading: Bool = false
    var enabled: Bool = true
    let action: () -> Void

    var body: some View {
        Button(action: action) {
            ZStack {
                if loading { ProgressView().tint(Color.danger) } else { Text(title).fontWeight(.bold) }
            }
            .frame(maxWidth: .infinity, minHeight: 56)
        }
        .background(Color.danger.tintFill, in: Capsule())
        .overlay(Capsule().strokeBorder(Color.danger.tintStroke, lineWidth: 1))
        .foregroundStyle(Color.danger)
        .disabled(!enabled || loading)
        .opacity(enabled && !loading ? 1 : 0.5)
    }
}

// MARK: - Indicators

/// The tint formula as a square icon chip.
struct IconChip: View {
    let glyph: String
    let tone: Color
    var size: CGFloat = 36

    var body: some View {
        Text(glyph)
            .font(.system(size: size * 0.42))
            .frame(width: size, height: size)
            .tinted(tone, radius: BeebRadius.chip)
    }
}

/// Tinted status pill. Always carries text  color is never the only signal.
struct StatusBadge: View {
    let text: String
    let tone: Color

    var body: some View {
        HStack(spacing: 7) {
            Circle().fill(tone).frame(width: 6, height: 6)
            Text(text).font(.beebCaption).fontWeight(.semibold)
        }
        .padding(.horizontal, 12)
        .padding(.vertical, 6)
        .tinted(tone, radius: 999)
    }
}

/// Icon chip + big tabular value + muted caption.
/// The caption stays muted on purpose  color identifies the metric, not the text.
struct StatTile: View {
    let glyph: String
    let value: String
    let label: String
    let tone: Color

    var body: some View {
        VStack(alignment: .leading, spacing: 0) {
            IconChip(glyph: glyph, tone: tone)
            Text(value)
                .font(.beebNumeric)
                .fontWeight(.bold)
                .foregroundStyle(tone)
                .padding(.top, 12)
            Text(label)
                .font(.beebCaption)
                .foregroundStyle(Color.muted)
        }
        .frame(maxWidth: .infinity, alignment: .leading)
        .padding(16)
        .beebCard()
    }
}

/// Label on the leading edge, value on the trailing edge. The receipt/summary workhorse.
struct MetricRow: View {
    let glyph: String
    let label: String
    let value: String
    let tone: Color

    var body: some View {
        HStack {
            IconChip(glyph: glyph, tone: tone, size: 30)
            Text(label).font(.beebBody).foregroundStyle(Color.muted)
            Spacer()
            Text(value)
                .font(.beebNumeric)
                .foregroundStyle(tone)
                .numeric()
        }
        .padding(.horizontal, 16)
        .padding(.vertical, 12)
    }
}

/// Scooter battery, shifting to the warning tone below 20%.
/// Scooter battery.
///
/// `percent` is optional because "we have no reading yet" is a real state, and it is not the same
/// as zero. Rendering an unknown level as a red 0% tells the rider their scooter is flat when it
/// may be full, so an unknown level shows a dash and a flat neutral track instead.
struct BatteryBar: View {
    let percent: Int?
    let label: String
    let hint: String

    private var tone: Color {
        guard let percent else { return Color.muted }
        return percent < 20 ? Color.warning : Color.brand
    }

    var body: some View {
        VStack(alignment: .leading, spacing: 10) {
            HStack {
                Text(label).font(.beebBody).foregroundStyle(Color.muted)
                Spacer()
                Text(percent.map { "\($0)%" } ?? "\u{2014}")
                    .font(.beebNumeric).foregroundStyle(tone).numeric()
            }
            GeometryReader { geo in
                ZStack(alignment: .leading) {
                    Capsule().fill(Color.lineStrong)
                    Capsule().fill(tone)
                        .frame(width: geo.size.width * CGFloat(min(max(percent ?? 0, 0), 100)) / 100)
                }
            }
            .frame(height: 6)
            Text(hint).font(.beebCaption).foregroundStyle(Color.muted)
        }
        .padding(16)
        .beebCard()
    }
}

/// The one display-size number on a screen (the timer, the balance, the fare).
struct DisplayNumber: View {
    let value: String
    let caption: String
    var tone: Color = .brand

    var body: some View {
        VStack(spacing: 6) {
            Text(caption).font(.beebCaption).foregroundStyle(Color.muted)
            Text(value)
                .font(.beebDisplaySmall)
                .foregroundStyle(tone)
                .numeric()
        }
        .frame(maxWidth: .infinity)
    }
}

/// Big circular status mark at the top of a result screen.
struct StatusMark: View {
    let systemName: String
    let tone: Color

    var body: some View {
        Image(systemName: systemName)
            .font(.system(size: 34, weight: .bold))
            .foregroundStyle(Color.brandInk)
            .frame(width: 76, height: 76)
            .background(tone, in: Circle())
            .beebGlow(tone)
    }
}

// MARK: - Containers

extension View {
    /// Standard card: 20pt radius, hairline border, no shadow in dark.
    func beebCard() -> some View {
        self
            .frame(maxWidth: .infinity, alignment: .leading)
            .background(Color.surface, in: RoundedRectangle(cornerRadius: BeebRadius.card))
            .overlay(
                RoundedRectangle(cornerRadius: BeebRadius.card)
                    .strokeBorder(Color.line, lineWidth: 1)
            )
    }

    /// Legacy alias kept so existing screens keep compiling.
    func card() -> some View { padding().beebCard() }

    /// Legacy alias  the brand-tinted variant is now just a tinted card.
    func brandCard() -> some View {
        padding()
            .frame(maxWidth: .infinity, alignment: .leading)
            .tinted(Color.brand, radius: BeebRadius.card)
            .foregroundStyle(Color.appForeground)
    }
}
