//
//  ResultBannerView.swift
//  Baccarat
//
//  Animated result banner showing the winner and itemized bet results.
//

import SwiftUI
import CasinoKit

/// An animated banner showing the round result with bet breakdown.
struct ResultBannerView: View {
    let result: GameResult
    let totalWinnings: Int
    let betResults: [BetResult]
    var playerHadPair: Bool = false
    var bankerHadPair: Bool = false
    let currentBalance: Int
    let minBet: Int
    let onNewRound: () -> Void
    let onGameOver: () -> Void
    
    /// Whether the player is out of money and can't continue.
    private var isGameOver: Bool {
        currentBalance < minBet
    }
    
    @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
    
    @Environment(\.horizontalSizeClass) private var horizontalSizeClass
    
    /// Maximum width for the banner card on iPad
    private var maxBannerWidth: CGFloat {
        horizontalSizeClass == .regular ? CasinoDesign.Size.maxModalWidth : .infinity
    }
    
    // MARK: - Scaled Font Sizes (Dynamic Type)
    
    @ScaledMetric(relativeTo: .largeTitle) private var resultFontSize: CGFloat = Design.BaseFontSize.largeTitle
    @ScaledMetric(relativeTo: .title3) private var totalFontSize: CGFloat = Design.BaseFontSize.xxLarge + Design.Spacing.xSmall
    @ScaledMetric(relativeTo: .body) private var itemFontSize: CGFloat = Design.BaseFontSize.medium
    
    // MARK: - Computed Properties
    
    private var winningBets: [BetResult] {
        betResults.filter { $0.isWin }
    }
    
    private var losingBets: [BetResult] {
        betResults.filter { $0.isLoss }
    }
    
    private var pushBets: [BetResult] {
        betResults.filter { $0.isPush }
    }
    
    var body: some View {
        ZStack {
            // Background overlay
            Color.black.opacity(showBanner ? Design.Opacity.medium : 0)
                .ignoresSafeArea()
                .animation(.easeIn(duration: Design.Animation.fadeInDuration), value: showBanner)
            
            // Banner
            VStack(spacing: Design.Spacing.medium) {
                // Result text
                Text(result.displayText)
                    .font(.system(size: resultFontSize, weight: .black, design: .rounded))
                    .foregroundStyle(
                        LinearGradient(
                            colors: [.white, result.color],
                            startPoint: .top,
                            endPoint: .bottom
                        )
                    )
                    .shadow(color: result.color.opacity(Design.Opacity.heavy), radius: Design.Shadow.radiusLarge)
                    .scaleEffect(showText ? Design.Scale.normal : Design.Scale.shrunk)
                    .opacity(showText ? Design.Scale.normal : 0)
                
                // Pair indicators
                if playerHadPair || bankerHadPair {
                    HStack(spacing: Design.Spacing.large) {
                        if playerHadPair {
                            PairBadge(label: "P PAIR", color: .blue)
                        }
                        if bankerHadPair {
                            PairBadge(label: "B PAIR", color: .red)
                        }
                    }
                    .scaleEffect(showBreakdown ? Design.Scale.normal : Design.Scale.shrunk)
                    .opacity(showBreakdown ? Design.Scale.normal : 0)
                }
                
                // Bet breakdown
                if !betResults.isEmpty {
                    BetBreakdownView(
                        winningBets: winningBets,
                        losingBets: losingBets,
                        pushBets: pushBets,
                        fontSize: itemFontSize
                    )
                    .scaleEffect(showBreakdown ? Design.Scale.normal : Design.Scale.shrunk)
                    .opacity(showBreakdown ? Design.Scale.normal : 0)
                }
                
                // Total
                if totalWinnings != 0 {
                    HStack(spacing: Design.Spacing.small) {
                        Text("TOTAL")
                            .font(.system(size: Design.BaseFontSize.body, weight: .bold))
                            .foregroundStyle(.white.opacity(Design.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)
                        }
                    }
                    .scaleEffect(showTotal ? Design.Scale.normal : Design.Scale.shrunk)
                    .opacity(showTotal ? Design.Scale.normal : 0)
                }
                
                // Game Over message or New Round button
                if isGameOver {
                    // Game Over - show message and restart button
                    VStack(spacing: Design.Spacing.medium) {
                        Text(String(localized: "You've run out of chips!"))
                            .font(.system(size: Design.BaseFontSize.medium, weight: .medium))
                            .foregroundStyle(.red.opacity(Design.Opacity.heavy))
                        
                        Button {
                            onGameOver()
                        } label: {
                            HStack(spacing: Design.Spacing.small) {
                                Image(systemName: "arrow.counterclockwise")
                                Text(String(localized: "Play Again"))
                            }
                            .font(.system(size: Design.BaseFontSize.xLarge, weight: .bold))
                            .foregroundStyle(.black)
                            .padding(.horizontal, Design.Spacing.xxxLarge + Design.Spacing.small)
                            .padding(.vertical, Design.Spacing.medium + Design.Spacing.xxSmall)
                            .background(
                                Capsule()
                                    .fill(
                                        LinearGradient(
                                            colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
                                            startPoint: .top,
                                            endPoint: .bottom
                                        )
                                    )
                            )
                            .shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
                        }
                    }
                    .scaleEffect(showButton ? Design.Scale.normal : Design.Scale.shrunk)
                    .opacity(showButton ? Design.Scale.normal : 0)
                    .padding(.top, Design.Spacing.small)
                } else {
                    // Normal - New Round button
                    Button {
                        onNewRound()
                    } label: {
                        Text(String(localized: "New Round"))
                            .font(.system(size: Design.BaseFontSize.xLarge, weight: .bold))
                            .foregroundStyle(.black)
                            .padding(.horizontal, Design.Spacing.xxxLarge + Design.Spacing.small)
                            .padding(.vertical, Design.Spacing.medium + Design.Spacing.xxSmall)
                            .background(
                                Capsule()
                                    .fill(
                                        LinearGradient(
                                            colors: [Color.CasinoButton.goldLight, Color.CasinoButton.goldDark],
                                            startPoint: .top,
                                            endPoint: .bottom
                                        )
                                    )
                            )
                            .shadow(color: .yellow.opacity(Design.Opacity.light), radius: Design.Shadow.radiusMedium)
                    }
                    .scaleEffect(showButton ? Design.Scale.normal : Design.Scale.shrunk)
                    .opacity(showButton ? Design.Scale.normal : 0)
                    .padding(.top, Design.Spacing.small)
                }
            }
            .padding(.horizontal, Design.Spacing.xLarge)
            .padding(.vertical, Design.Spacing.xxLarge)
            .frame(maxWidth: maxBannerWidth)
            .background(
                RoundedRectangle(cornerRadius: Design.CornerRadius.xxLarge)
                    .fill(
                        LinearGradient(
                            colors: [
                                Color(white: 0.15),
                                Color(white: 0.08)
                            ],
                            startPoint: .top,
                            endPoint: .bottom
                        )
                    )
                    .overlay(
                        RoundedRectangle(cornerRadius: Design.CornerRadius.xxLarge)
                            .strokeBorder(
                                LinearGradient(
                                    colors: [
                                        result.color.opacity(Design.Opacity.heavy),
                                        result.color.opacity(Design.Opacity.light)
                                    ],
                                    startPoint: .topLeading,
                                    endPoint: .bottomTrailing
                                ),
                                lineWidth: Design.LineWidth.thick
                            )
                    )
            )
            .shadow(color: result.color.opacity(Design.Opacity.light), radius: Design.Shadow.radiusXXLarge)
            .padding(.horizontal, Design.Spacing.large)
            .scaleEffect(showBanner ? Design.Scale.normal : Design.Scale.slightShrink)
            .opacity(showBanner ? Design.Scale.normal : 0)
        }
        .onAppear {
            withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce)) {
                showBanner = true
            }
            
            withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce).delay(Design.Animation.staggerDelay1)) {
                showText = true
            }
            
            withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce).delay(Design.Animation.staggerDelay2)) {
                showBreakdown = true
            }
            
            withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce).delay(Design.Animation.staggerDelay3)) {
                showTotal = true
            }
            
            // Show button after everything else
            withAnimation(.spring(duration: Design.Animation.springDuration, bounce: Design.Animation.springBounce).delay(Design.Animation.staggerDelay3 + Design.Animation.staggerDelay1)) {
                showButton = true
            }
            
            // Play game over sound if out of chips (after a short delay so it doesn't overlap with lose sound)
            if isGameOver {
                Task {
                    try? await Task.sleep(for: .seconds(1))
                    SoundManager.shared.play(.gameOver)
                }
            }
            
            // Announce result to VoiceOver users
            announceResult()
        }
        .accessibilityElement(children: .ignore)
        .accessibilityLabel(accessibilityDescription)
    }
    
    // MARK: - Accessibility
    
    private var accessibilityDescription: String {
        var description = result.displayText
        
        // Add pair information
        if playerHadPair {
            description += ". Player pair"
        }
        if bankerHadPair {
            description += ". Banker pair"
        }
        
        // Add bet results
        for bet in winningBets {
            description += ". \(bet.displayName) won \(bet.payout)"
        }
        for bet in losingBets {
            description += ". \(bet.displayName) lost \(abs(bet.payout))"
        }
        
        // Add total
        if totalWinnings > 0 {
            description += ". Total winnings: \(totalWinnings)"
        } else if totalWinnings < 0 {
            description += ". Total loss: \(abs(totalWinnings))"
        }
        
        return description
    }
    
    private func announceResult() {
        Task { @MainActor in
            try? await Task.sleep(for: .milliseconds(500))
            AccessibilityNotification.Announcement(accessibilityDescription).post()
        }
    }
}

// MARK: - Bet Breakdown View

private struct BetBreakdownView: View {
    let winningBets: [BetResult]
    let losingBets: [BetResult]
    let pushBets: [BetResult]
    let fontSize: CGFloat
    
    var body: some View {
        VStack(spacing: Design.Spacing.xSmall) {
            // Winning bets
            ForEach(winningBets) { bet in
                BetResultRow(bet: bet, fontSize: fontSize)
            }
            
            // Push bets
            ForEach(pushBets) { bet in
                BetResultRow(bet: bet, fontSize: fontSize)
            }
            
            // Losing bets
            ForEach(losingBets) { bet in
                BetResultRow(bet: bet, fontSize: fontSize)
            }
        }
        .padding(.horizontal, Design.Spacing.medium)
        .padding(.vertical, Design.Spacing.small)
        .background(
            RoundedRectangle(cornerRadius: Design.CornerRadius.medium)
                .fill(Color.white.opacity(Design.Opacity.verySubtle))
        )
    }
}

// MARK: - Bet Result Row

private struct BetResultRow: View {
    let bet: BetResult
    let fontSize: CGFloat
    
    private var statusColor: Color {
        if bet.isWin { return .green }
        if bet.isLoss { return .red }
        return .yellow  // Push
    }
    
    private var statusIcon: String {
        if bet.isWin { return "checkmark.circle.fill" }
        if bet.isLoss { return "xmark.circle.fill" }
        return "arrow.left.arrow.right.circle.fill"  // Push
    }
    
    private var payoutText: String {
        if bet.isWin { return "+\(bet.payout)" }
        if bet.isLoss { return "\(bet.payout)" }
        return "PUSH"
    }
    
    var body: some View {
        HStack(spacing: Design.Spacing.small) {
            // Status icon
            Image(systemName: statusIcon)
                .font(.system(size: fontSize))
                .foregroundStyle(statusColor)
            
            // Bet name
            Text(bet.displayName)
                .font(.system(size: fontSize, weight: .medium))
                .foregroundStyle(.white.opacity(Design.Opacity.heavy))
            
            Spacer()
            
            // Payout
            Text(payoutText)
                .font(.system(size: fontSize, weight: .bold, design: .rounded))
                .foregroundStyle(statusColor)
        }
    }
}

// MARK: - Pair Badge

private struct PairBadge: View {
    let label: String
    let color: Color
    
    var body: some View {
        Text(label)
            .font(.system(size: Design.BaseFontSize.callout - Design.Spacing.xxSmall, weight: .bold))
            .foregroundStyle(.white)
            .padding(.horizontal, Design.Spacing.small)
            .padding(.vertical, Design.Spacing.xxSmall)
            .background(
                Capsule()
                    .fill(color)
            )
    }
}

// Note: ConfettiView is now provided by CasinoKit

#Preview("Win") {
    ZStack {
        Color.Table.preview
            .ignoresSafeArea()
        
        ResultBannerView(
            result: .playerWins,
            totalWinnings: 1500,
            betResults: [
                BetResult(type: .player, amount: 1000, payout: 1000),
                BetResult(type: .playerPair, amount: 100, payout: 1100),
                BetResult(type: .dragonBonusPlayer, amount: 100, payout: 200),
                BetResult(type: .tie, amount: 500, payout: -500)
            ],
            playerHadPair: true,
            bankerHadPair: false,
            currentBalance: 5000,
            minBet: 10,
            onNewRound: {},
            onGameOver: {}
        )
    }
}

#Preview("Game Over") {
    ZStack {
        Color.Table.preview
            .ignoresSafeArea()
        
        ResultBannerView(
            result: .bankerWins,
            totalWinnings: -1000,
            betResults: [
                BetResult(type: .player, amount: 1000, payout: -1000)
            ],
            playerHadPair: false,
            bankerHadPair: false,
            currentBalance: 0,
            minBet: 10,
            onNewRound: {},
            onGameOver: {}
        )
    }
}
