//
//  ResultBannerView.swift
//  CasinoKit
//
//  A reusable animated result banner for casino games.
//  Each game provides its own breakdown content via a @ViewBuilder closure.
//

import SwiftUI

/// A reusable result banner with staggered animations.
///
/// This component provides the shared structure for result displays:
/// - Animated dark overlay
/// - Result text with gradient and glow
/// - Game-specific breakdown content (provided via @ViewBuilder)
/// - Total winnings display
/// - New Round / Play Again button
/// - Game over handling
///
/// Usage:
/// ```swift
/// CasinoResultBannerView(
///     resultText: "WIN!",
///     resultColor: .green,
///     totalWinnings: 500,
///     currentBalance: 10500,
///     minBet: 10,
///     breakdownContent: {
///         // Your game-specific breakdown views here
///         ForEach(betResults) { bet in
///             BetResultRow(bet: bet)
///         }
///     },
///     onNewRound: { startNewRound() },
///     onPlayAgain: { resetGame() }
/// )
/// ```
public struct CasinoResultBannerView<Content: View>: View {
    
    // MARK: - Parameters
    
    /// The result text to display (e.g., "WIN!", "PLAYER WINS", "BLACKJACK!")
    public let resultText: String
    
    /// The color associated with the result (green for win, red for loss, etc.)
    public let resultColor: Color
    
    /// Total winnings/losses for this round
    public let totalWinnings: Int
    
    /// Current balance to determine if game over
    public let currentBalance: Int
    
    /// Minimum bet to determine if player can continue
    public let minBet: Int
    
    /// Game-specific breakdown content (bet results, hand results, etc.)
    @ViewBuilder public let breakdownContent: Content
    
    /// Action when "New Round" is tapped
    public let onNewRound: () -> Void
    
    /// Action when "Play Again" is tapped (game over state)
    public let onPlayAgain: () -> Void
    
    // MARK: - Animation States
    
    @State private var showBanner = false
    @State private var showText = false
    @State private var showBreakdown = false
    @State private var showTotal = false
    @State private var showButton = false
    
    // MARK: - Environment
    
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    
    // MARK: - Scaled Font Sizes (Dynamic Type)
    
    @ScaledMetric(relativeTo: .largeTitle) private var resultFontSize: CGFloat = CasinoDesign.BaseFontSize.largeTitle
    @ScaledMetric(relativeTo: .title3) private var totalFontSize: CGFloat = CasinoDesign.BaseFontSize.xxLarge + CasinoDesign.Spacing.xSmall
    @ScaledMetric(relativeTo: .headline) private var buttonFontSize: CGFloat = CasinoDesign.BaseFontSize.xLarge
    @ScaledMetric(relativeTo: .title) private var gameOverFontSize: CGFloat = CasinoDesign.BaseFontSize.xxLarge
    
    // MARK: - Computed Properties
    
    /// Whether the player is out of money and can't continue.
    private var isGameOver: Bool {
        currentBalance < minBet
    }
    
    /// Maximum width for the banner card on iPad
    private var maxBannerWidth: CGFloat {
        horizontalSizeClass == .regular ? CasinoDesign.Size.maxModalWidth : .infinity
    }
    
    // MARK: - Initializer
    
    /// Creates a result banner view.
    /// - Parameters:
    ///   - resultText: The main result text to display.
    ///   - resultColor: The color for the result (affects text gradient, border, shadow).
    ///   - totalWinnings: The total amount won or lost this round.
    ///   - currentBalance: The player's current balance (for game over detection).
    ///   - minBet: The minimum bet amount (for game over detection).
    ///   - breakdownContent: Game-specific content showing bet/hand breakdown.
    ///   - onNewRound: Action when "New Round" button is tapped.
    ///   - onPlayAgain: Action when "Play Again" button is tapped (game over state).
    public init(
        resultText: String,
        resultColor: Color,
        totalWinnings: Int,
        currentBalance: Int,
        minBet: Int,
        @ViewBuilder breakdownContent: () -> Content,
        onNewRound: @escaping () -> Void,
        onPlayAgain: @escaping () -> Void
    ) {
        self.resultText = resultText
        self.resultColor = resultColor
        self.totalWinnings = totalWinnings
        self.currentBalance = currentBalance
        self.minBet = minBet
        self.breakdownContent = breakdownContent()
        self.onNewRound = onNewRound
        self.onPlayAgain = onPlayAgain
    }
    
    // MARK: - Body
    
    public var body: some View {
        ZStack {
            // Background overlay
            Color.black.opacity(showBanner ? CasinoDesign.Opacity.medium : 0)
                .ignoresSafeArea()
                .animation(.easeIn(duration: CasinoDesign.Animation.fadeInDuration), value: showBanner)
            
            // Banner card
            VStack(spacing: CasinoDesign.Spacing.medium) {
                // Game Over header (shown prominently at top when out of chips)
                if isGameOver {
                    VStack(spacing: CasinoDesign.Spacing.xSmall) {
                        Text(String(localized: "GAME OVER", bundle: .module))
                            .font(.system(size: gameOverFontSize, weight: .black, design: .rounded))
                            .foregroundStyle(.red)
                        
                        Text(String(localized: "You've run out of chips!", bundle: .module))
                            .font(.system(size: CasinoDesign.BaseFontSize.medium, weight: .medium))
                            .foregroundStyle(.white.opacity(CasinoDesign.Opacity.strong))
                    }
                    .scaleEffect(showText ? CasinoDesign.Scale.normal : CasinoDesign.Scale.shrunk)
                    .opacity(showText ? CasinoDesign.Scale.normal : 0)
                }
                
                // Result text with gradient and glow (smaller when game over)
                Text(resultText)
                    .font(.system(size: isGameOver ? resultFontSize * 0.7 : resultFontSize, weight: .black, design: .rounded))
                    .foregroundStyle(
                        LinearGradient(
                            colors: [.white, resultColor],
                            startPoint: .top,
                            endPoint: .bottom
                        )
                    )
                    .shadow(color: resultColor.opacity(CasinoDesign.Opacity.heavy), radius: CasinoDesign.Shadow.radiusLarge)
                    .scaleEffect(showText ? CasinoDesign.Scale.normal : CasinoDesign.Scale.shrunk)
                    .opacity(showText ? CasinoDesign.Scale.normal : 0)
                
                // Game-specific breakdown content
                breakdownContent
                    .scaleEffect(showBreakdown ? CasinoDesign.Scale.normal : CasinoDesign.Scale.shrunk)
                    .opacity(showBreakdown ? CasinoDesign.Scale.normal : 0)
                
                // Total winnings
                if totalWinnings != 0 {
                    totalWinningsView
                        .scaleEffect(showTotal ? CasinoDesign.Scale.normal : CasinoDesign.Scale.shrunk)
                        .opacity(showTotal ? CasinoDesign.Scale.normal : 0)
                }
                
                // Button section
                buttonSection
                    .scaleEffect(showButton ? CasinoDesign.Scale.normal : CasinoDesign.Scale.shrunk)
                    .opacity(showButton ? CasinoDesign.Scale.normal : 0)
                    .padding(.top, CasinoDesign.Spacing.small)
            }
            .padding(.horizontal, CasinoDesign.Spacing.xLarge)
            .padding(.vertical, CasinoDesign.Spacing.xxLarge)
            .frame(maxWidth: maxBannerWidth)
            .background(bannerBackground)
            .shadow(color: resultColor.opacity(CasinoDesign.Opacity.light), radius: CasinoDesign.Shadow.radiusXXLarge)
            .padding(.horizontal, CasinoDesign.Spacing.large)
            .scaleEffect(showBanner ? CasinoDesign.Scale.normal : CasinoDesign.Scale.slightShrink)
            .opacity(showBanner ? CasinoDesign.Scale.normal : 0)
        }
        .onAppear {
            startAnimations()
        }
        .accessibilityElement(children: .ignore)
        .accessibilityLabel(accessibilityDescription)
    }
    
    // MARK: - Subviews
    
    private var totalWinningsView: some View {
        HStack(spacing: CasinoDesign.Spacing.small) {
            Text(String(localized: "TOTAL", bundle: .module))
                .font(.system(size: CasinoDesign.BaseFontSize.body, weight: .bold))
                .foregroundStyle(.white.opacity(CasinoDesign.Opacity.accent))
            
            if totalWinnings > 0 {
                Text("+\(totalWinnings)")
                    .font(.system(size: totalFontSize, weight: .black, design: .rounded))
                    .foregroundStyle(.green)
            } else {
                Text("\(totalWinnings)")
                    .font(.system(size: totalFontSize, weight: .black, design: .rounded))
                    .foregroundStyle(.red)
            }
        }
    }
    
    @ViewBuilder
    private var buttonSection: some View {
        if isGameOver {
            // Game Over - show restart button (message is at top)
            Button {
                onPlayAgain()
            } label: {
                HStack(spacing: CasinoDesign.Spacing.small) {
                    Image(systemName: "arrow.counterclockwise")
                    Text(String(localized: "Play Again", bundle: .module))
                }
                .font(.system(size: buttonFontSize, weight: .bold))
                .foregroundStyle(.black)
                .padding(.horizontal, CasinoDesign.Spacing.xxxLarge + CasinoDesign.Spacing.small)
                .padding(.vertical, CasinoDesign.Spacing.medium + CasinoDesign.Spacing.xxSmall)
                .background(goldButtonBackground)
            }
        } else {
            // Normal - New Round button
            Button {
                onNewRound()
            } label: {
                Text(String(localized: "New Round", bundle: .module))
                    .font(.system(size: buttonFontSize, weight: .bold))
                    .foregroundStyle(.black)
                    .padding(.horizontal, CasinoDesign.Spacing.xxxLarge + CasinoDesign.Spacing.small)
                    .padding(.vertical, CasinoDesign.Spacing.medium + CasinoDesign.Spacing.xxSmall)
                    .background(goldButtonBackground)
            }
        }
    }
    
    private var goldButtonBackground: some View {
        Capsule()
            .fill(
                LinearGradient(
                    colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
                    startPoint: .top,
                    endPoint: .bottom
                )
            )
            .shadow(color: .yellow.opacity(CasinoDesign.Opacity.light), radius: CasinoDesign.Shadow.radiusMedium)
    }
    
    private var bannerBackground: some View {
        RoundedRectangle(cornerRadius: CasinoDesign.CornerRadius.xxLarge)
            .fill(
                LinearGradient(
                    colors: [
                        Color.CasinoModal.backgroundLight,
                        Color.CasinoModal.backgroundDark
                    ],
                    startPoint: .top,
                    endPoint: .bottom
                )
            )
            .overlay(
                RoundedRectangle(cornerRadius: CasinoDesign.CornerRadius.xxLarge)
                    .strokeBorder(
                        LinearGradient(
                            colors: [
                                resultColor.opacity(CasinoDesign.Opacity.heavy),
                                resultColor.opacity(CasinoDesign.Opacity.light)
                            ],
                            startPoint: .topLeading,
                            endPoint: .bottomTrailing
                        ),
                        lineWidth: CasinoDesign.LineWidth.thick
                    )
            )
    }
    
    // MARK: - Animations
    
    private func startAnimations() {
        withAnimation(.spring(duration: CasinoDesign.Animation.springDuration, bounce: CasinoDesign.Animation.springBounce)) {
            showBanner = true
        }
        
        withAnimation(.spring(duration: CasinoDesign.Animation.springDuration, bounce: CasinoDesign.Animation.springBounce).delay(CasinoDesign.Animation.staggerDelay1)) {
            showText = true
        }
        
        withAnimation(.spring(duration: CasinoDesign.Animation.springDuration, bounce: CasinoDesign.Animation.springBounce).delay(CasinoDesign.Animation.staggerDelay2)) {
            showBreakdown = true
        }
        
        withAnimation(.spring(duration: CasinoDesign.Animation.springDuration, bounce: CasinoDesign.Animation.springBounce).delay(CasinoDesign.Animation.staggerDelay3)) {
            showTotal = true
        }
        
        // Show button after everything else
        withAnimation(.spring(duration: CasinoDesign.Animation.springDuration, bounce: CasinoDesign.Animation.springBounce).delay(CasinoDesign.Animation.staggerDelay3 + CasinoDesign.Animation.staggerDelay1)) {
            showButton = true
        }
        
        // Play game over sound if out of chips
        if isGameOver {
            Task {
                try? await Task.sleep(for: .seconds(1))
                SoundManager.shared.play(.gameOver)
            }
        }
        
        // Announce result to VoiceOver users
        announceResult()
    }
    
    // MARK: - Accessibility
    
    private var accessibilityDescription: String {
        var description = resultText
        
        if totalWinnings > 0 {
            description += ". " + String(localized: "Total winnings: \(totalWinnings)", bundle: .module)
        } else if totalWinnings < 0 {
            description += ". " + String(localized: "Total loss: \(abs(totalWinnings))", bundle: .module)
        }
        
        if isGameOver {
            description += ". " + String(localized: "Game over. You've run out of chips.", bundle: .module)
        }
        
        return description
    }
    
    private func announceResult() {
        Task { @MainActor in
            try? await Task.sleep(for: .milliseconds(500))
            AccessibilityNotification.Announcement(accessibilityDescription).post()
        }
    }
}

// MARK: - Result Breakdown Card

/// A styled container for bet/hand breakdown content.
/// Provides consistent styling across all casino games.
public struct ResultBreakdownCard<Content: View>: View {
    @ViewBuilder public let content: Content
    
    public init(@ViewBuilder content: () -> Content) {
        self.content = content()
    }
    
    public var body: some View {
        VStack(spacing: CasinoDesign.Spacing.xSmall) {
            content
        }
        .padding(.horizontal, CasinoDesign.Spacing.medium)
        .padding(.vertical, CasinoDesign.Spacing.small)
        .background(
            RoundedRectangle(cornerRadius: CasinoDesign.CornerRadius.medium)
                .fill(Color.white.opacity(CasinoDesign.Opacity.verySubtle))
        )
    }
}

// MARK: - Result Row

/// A generic row for displaying a result item with label, optional amount, and status.
public struct ResultItemRow: View {
    public let label: String
    public let statusText: String
    public let statusColor: Color
    public var amount: Int?
    public var statusIcon: String?
    
    @ScaledMetric(relativeTo: .body) private var fontSize: CGFloat = CasinoDesign.BaseFontSize.medium
    
    public init(
        label: String,
        statusText: String,
        statusColor: Color,
        amount: Int? = nil,
        statusIcon: String? = nil
    ) {
        self.label = label
        self.statusText = statusText
        self.statusColor = statusColor
        self.amount = amount
        self.statusIcon = statusIcon
    }
    
    private var amountText: String? {
        guard let amount = amount else { return nil }
        if amount > 0 {
            return "+\(amount)"
        } else if amount < 0 {
            return "\(amount)"
        } else {
            return nil
        }
    }
    
    private var amountColor: Color {
        guard let amount = amount else { return .white }
        if amount > 0 { return .green }
        if amount < 0 { return .red }
        return .blue
    }
    
    public var body: some View {
        HStack(spacing: CasinoDesign.Spacing.small) {
            // Status icon (if provided)
            if let icon = statusIcon {
                Image(systemName: icon)
                    .font(.system(size: fontSize))
                    .foregroundStyle(statusColor)
            }
            
            // Label
            Text(label)
                .font(.system(size: fontSize, weight: .medium))
                .foregroundStyle(.white.opacity(CasinoDesign.Opacity.heavy))
            
            Spacer()
            
            // Amount (if provided)
            if let amountText = amountText {
                Text(amountText)
                    .font(.system(size: fontSize, weight: .semibold, design: .rounded))
                    .foregroundStyle(amountColor)
            }
            
            // Status text
            Text(statusText)
                .font(.system(size: fontSize + 2, weight: .bold))
                .foregroundStyle(statusColor)
        }
    }
}

// MARK: - Preview

#Preview("Win Result") {
    ZStack {
        Color.CasinoTable.felt
            .ignoresSafeArea()
        
        CasinoResultBannerView(
            resultText: "WIN!",
            resultColor: .green,
            totalWinnings: 500,
            currentBalance: 10500,
            minBet: 10,
            breakdownContent: {
                ResultBreakdownCard {
                    ResultItemRow(
                        label: "Main Hand",
                        statusText: "WIN",
                        statusColor: .green,
                        amount: 500,
                        statusIcon: "checkmark.circle.fill"
                    )
                }
            },
            onNewRound: {},
            onPlayAgain: {}
        )
    }
}

#Preview("Game Over") {
    ZStack {
        Color.CasinoTable.felt
            .ignoresSafeArea()
        
        CasinoResultBannerView(
            resultText: "LOSE",
            resultColor: .red,
            totalWinnings: -100,
            currentBalance: 0,
            minBet: 10,
            breakdownContent: {
                ResultBreakdownCard {
                    ResultItemRow(
                        label: "Main Hand",
                        statusText: "BUST",
                        statusColor: .red,
                        amount: -100,
                        statusIcon: "xmark.circle.fill"
                    )
                }
            },
            onNewRound: {},
            onPlayAgain: {}
        )
    }
}

