import SessionCore
import SwiftUI

/// Copy + wire pairing for one gate button — the SINGLE label source for both
/// gate surfaces (`GateBanner`, `PlanGateSheet`). Labels mirror
/// public/tabs.ts:334-350 byte-for-byte; the affordance→ClientMessage mapping
/// itself is frozen in SessionCore (`GateState.Affordance.clientMessage`).
struct GateChoiceSpec: Equatable {
    let label: String
    let affordance: GateState.Affordance

    /// Ordered button set for `gate` (tool → two, plan → three), driven by the
    /// frozen `GateState.affordances` list.
    static func specs(for gate: GateState) -> [GateChoiceSpec] {
        gate.affordances.map { GateChoiceSpec(label: label(for: $0), affordance: $0) }
    }

    static func label(for affordance: GateState.Affordance) -> String {
        switch affordance {
        case .approveAuto: return "✓ Approve + Auto"
        case .approveReview: return "✓ Approve + Review"
        case .keepPlanning: return "✎ Keep Planning"
        case .approve: return "✓ Approve"
        case .reject: return "✗ Reject"
        }
    }
}

/// T-iOS-14 · Two-button banner for an ordinary TOOL gate (plan gates get the
/// three-way `PlanGateSheet`). Render-only: state lives in `GateViewModel`.
/// Every tap reports the affordance PLUS the epoch of the gate THIS banner
/// rendered — the VM drops stale taps (first-line guard); wiring into
/// TerminalScreen is T-iOS-15.
struct GateBanner: View {
    let gate: GateState
    let onDecide: (GateState.Affordance, Int) -> Void

    private enum Copy {
        /// Chinese lead-in above the (web-mirrored) English tool line — makes the
        /// "this needs me" intent unmissable at a glance.
        static let heading = "需要你的确认"
    }

    private enum Metrics {
        static let messageLineLimit = 2
    }

    /// Banner headline, mirror of public/tabs.ts:329:
    /// `Claude wants to use ${pendingTool ?? 'a tool'}`. `detail` is
    /// server-supplied display text (untrusted) — rendered as plain Text only.
    static func message(for gate: GateState) -> String {
        "Claude wants to use \(gate.detail ?? "a tool")"
    }

    /// A prominent Card (the gate is THE core action — approve/reject a shell
    /// command). An amber "needs me" badge heads it, the tool line reads big and
    /// clear, and full-width DS buttons give unmissable tap targets.
    var body: some View {
        Card {
            VStack(alignment: .leading, spacing: DS.Space.md12) {
                header
                Text(Self.message(for: gate))
                    .font(DS.Typography.body.weight(.semibold))
                    .foregroundStyle(DS.Palette.textPrimary)
                    .lineLimit(Metrics.messageLineLimit)
                    .fixedSize(horizontal: false, vertical: true)
                buttonRow
            }
        }
        .accessibilityElement(children: .contain)
    }

    private var header: some View {
        HStack(spacing: DS.Space.sm8) {
            StatusBadge(status: .pendingApproval)
            Text(Copy.heading)
                .font(DS.Typography.caption)
                .foregroundStyle(DS.Palette.textSecondary)
        }
    }

    private var buttonRow: some View {
        HStack(spacing: DS.Space.sm8) {
            ForEach(GateChoiceSpec.specs(for: gate), id: \.affordance) { spec in
                decisionButton(spec)
            }
        }
    }

    private func decisionButton(_ spec: GateChoiceSpec) -> some View {
        Button(spec.label) {
            onDecide(spec.affordance, gate.epoch) // epoch of the RENDERED gate
        }
        .buttonStyle(DSButtonStyle(kind: kind(for: spec.affordance)))
        .accessibilityIdentifier("gate.decision.\(spec.affordance)")
    }

    /// Approve reads as the accent-filled primary, Reject as the destructive
    /// red; Keep Planning (never on a tool gate, but mapped for completeness)
    /// is the tinted secondary.
    private func kind(for affordance: GateState.Affordance) -> DSButtonStyle.Kind {
        switch affordance {
        case .approve, .approveAuto, .approveReview: return .primary
        case .reject: return .destructive
        case .keepPlanning: return .secondary
        }
    }
}
