//
//  CardStackView.swift
//  Blackjack
//
//  Shared card stack display for dealer and player hands.
//

import SwiftUI
import CasinoKit

/// A reusable view that displays a stack of cards with animations.
/// Used by both DealerHandView and PlayerHandView.
struct CardStackView: View {
    let cards: [Card]
    let cardWidth: CGFloat
    let cardSpacing: CGFloat
    let showAnimations: Bool
    let dealingSpeed: Double
    let showCardCount: Bool
    
    /// Determines if a card at a given index should be face up.
    /// For dealer: `{ index in index == 0 || showHoleCard }`
    /// For player: `{ _ in true }`
    let isFaceUp: (Int) -> Bool
    
    /// Animation offset for dealing cards (direction cards fly in from).
    let dealOffset: CGPoint
    
    /// Minimum number of card slots to reserve space for.
    /// This prevents width changes during dealing by pre-allocating placeholder space.
    let minimumCardSlots: Int
    
    /// Whether placeholders should use staggered (overlapped) layout like dealt cards.
    /// - `true`: Placeholders overlap using `cardSpacing` (use for bordered containers like player hand)
    /// - `false`: Placeholders side-by-side (use for borderless containers like dealer hand)
    let staggeredPlaceholders: Bool
    
    /// Number of additional placeholders needed to reach minimum slots.
    private var placeholdersNeeded: Int {
        max(0, minimumCardSlots - cards.count)
    }
    
    /// Spacing to use for empty placeholder state
    private var placeholderSpacing: CGFloat {
        staggeredPlaceholders ? cardSpacing : Design.Spacing.small
    }
    
    var body: some View {
        // Use staggered or side-by-side spacing based on configuration
        HStack(spacing: cards.isEmpty && placeholdersNeeded > 0 ? placeholderSpacing : cardSpacing) {
            if cards.isEmpty && placeholdersNeeded > 0 {
                // Show placeholders when empty
                ForEach(0..<placeholdersNeeded, id: \.self) { index in
                    CardPlaceholderView(width: cardWidth)
                        .zIndex(Double(index))
                }
            } else {
                // Show actual cards
                ForEach(cards.indices, id: \.self) { index in
                    let faceUp = isFaceUp(index)
                    CardView(
                        card: cards[index],
                        isFaceUp: faceUp,
                        cardWidth: cardWidth
                    )
                    .overlay(alignment: .bottomLeading) {
                        if showCardCount && faceUp {
                            HiLoCountBadge(card: cards[index])
                        }
                    }
                    .zIndex(Double(index))
                    .transition(
                        showAnimations
                        ? .asymmetric(
                            insertion: .offset(x: dealOffset.x, y: dealOffset.y)
                                .combined(with: .opacity)
                                .combined(with: .scale(scale: Design.Scale.slightShrink)),
                            removal: .scale.combined(with: .opacity)
                        )
                        : .identity
                    )
                }
                
                // Show trailing placeholders to reserve space for upcoming cards
                ForEach(0..<placeholdersNeeded, id: \.self) { index in
                    CardPlaceholderView(width: cardWidth)
                        .opacity(Design.Opacity.medium)
                        .zIndex(Double(cards.count + index))
                }
            }
        }
        .animation(
            showAnimations
            ? CasinoDesign.Animation.cardDeal(speed: dealingSpeed)
            : .none,
            value: cards.count
        )
    }
}

// MARK: - Convenience Initializers

extension CardStackView {
    /// Creates a card stack for the dealer (with hole card support).
    /// Uses side-by-side placeholders since dealer area has no border.
    static func dealer(
        cards: [Card],
        showHoleCard: Bool,
        cardWidth: CGFloat,
        cardSpacing: CGFloat,
        showAnimations: Bool,
        dealingSpeed: Double,
        showCardCount: Bool
    ) -> CardStackView {
        CardStackView(
            cards: cards,
            cardWidth: cardWidth,
            cardSpacing: cardSpacing,
            showAnimations: showAnimations,
            dealingSpeed: dealingSpeed,
            showCardCount: showCardCount,
            isFaceUp: { index in index == 0 || showHoleCard },
            dealOffset: CGPoint(
                x: Design.DealAnimation.dealerOffsetX,
                y: Design.DealAnimation.dealerOffsetY
            ),
            minimumCardSlots: 2,
            staggeredPlaceholders: false  // Side-by-side (no border to show shrink)
        )
    }
    
    /// Creates a card stack for the player (all cards face up).
    /// Uses staggered placeholders to match dealt card layout (prevents container shrink).
    /// - Parameter minimumCardSlots: Minimum slots to reserve (default 2 for initial deal).
    static func player(
        cards: [Card],
        cardWidth: CGFloat,
        cardSpacing: CGFloat,
        showAnimations: Bool,
        dealingSpeed: Double,
        showCardCount: Bool,
        minimumCardSlots: Int = 2
    ) -> CardStackView {
        CardStackView(
            cards: cards,
            cardWidth: cardWidth,
            cardSpacing: cardSpacing,
            showAnimations: showAnimations,
            dealingSpeed: dealingSpeed,
            showCardCount: showCardCount,
            isFaceUp: { _ in true },
            dealOffset: CGPoint(
                x: Design.DealAnimation.playerOffsetX,
                y: Design.DealAnimation.playerOffsetY
            ),
            minimumCardSlots: minimumCardSlots,
            staggeredPlaceholders: true  // Staggered (bordered container shows shrink)
        )
    }
}

// MARK: - Previews

#Preview("Empty - Staggered") {
    ZStack {
        Color.Table.felt.ignoresSafeArea()
        CardStackView(
            cards: [],
            cardWidth: 60,
            cardSpacing: -20,
            showAnimations: true,
            dealingSpeed: 1.0,
            showCardCount: false,
            isFaceUp: { _ in true },
            dealOffset: .zero,
            minimumCardSlots: 2,
            staggeredPlaceholders: true
        )
    }
}

#Preview("Empty - Side by Side") {
    ZStack {
        Color.Table.felt.ignoresSafeArea()
        CardStackView(
            cards: [],
            cardWidth: 60,
            cardSpacing: -20,
            showAnimations: true,
            dealingSpeed: 1.0,
            showCardCount: false,
            isFaceUp: { _ in true },
            dealOffset: .zero,
            minimumCardSlots: 2,
            staggeredPlaceholders: false
        )
    }
}

#Preview("Player Cards") {
    ZStack {
        Color.Table.felt.ignoresSafeArea()
        CardStackView.player(
            cards: [
                Card(suit: .hearts, rank: .ace),
                Card(suit: .spades, rank: .king)
            ],
            cardWidth: 60,
            cardSpacing: -20,
            showAnimations: true,
            dealingSpeed: 1.0,
            showCardCount: true
        )
    }
}

#Preview("Dealer - Hole Hidden") {
    ZStack {
        Color.Table.felt.ignoresSafeArea()
        CardStackView.dealer(
            cards: [
                Card(suit: .hearts, rank: .ace),
                Card(suit: .spades, rank: .king)
            ],
            showHoleCard: false,
            cardWidth: 60,
            cardSpacing: -20,
            showAnimations: true,
            dealingSpeed: 1.0,
            showCardCount: true
        )
    }
}

#Preview("Dealer - Hole Revealed") {
    ZStack {
        Color.Table.felt.ignoresSafeArea()
        CardStackView.dealer(
            cards: [
                Card(suit: .hearts, rank: .ace),
                Card(suit: .spades, rank: .king)
            ],
            showHoleCard: true,
            cardWidth: 60,
            cardSpacing: -20,
            showAnimations: true,
            dealingSpeed: 1.0,
            showCardCount: true
        )
    }
}

