// StateDiffer - Detects what changed between game states
// Generates movement instructions for the animation queue

class StateDiffer {
    constructor() {
        this.previousState = null;
    }

    // Compare old and new state, return array of movements
    diff(oldState, newState) {
        const movements = [];

        if (!oldState || !newState) {
            return movements;
        }

        // Check for initial flip phase - still animate initial flips
        if (oldState.waiting_for_initial_flip && !newState.waiting_for_initial_flip) {
            // Initial flip just completed - detect which cards were flipped
            for (const newPlayer of newState.players) {
                const oldPlayer = oldState.players.find(p => p.id === newPlayer.id);
                if (oldPlayer) {
                    for (let i = 0; i < 6; i++) {
                        if (!oldPlayer.cards[i].face_up && newPlayer.cards[i].face_up) {
                            movements.push({
                                type: 'flip',
                                playerId: newPlayer.id,
                                position: i,
                                faceUp: true,
                                card: newPlayer.cards[i]
                            });
                        }
                    }
                }
            }
            return movements;
        }

        // Still in initial flip selection - no animations
        if (newState.waiting_for_initial_flip) {
            return movements;
        }

        // Check for turn change - the previous player just acted
        const previousPlayerId = oldState.current_player_id;
        const currentPlayerId = newState.current_player_id;
        const turnChanged = previousPlayerId !== currentPlayerId;

        // Detect if a swap happened (discard changed AND a hand position changed)
        const newTop = newState.discard_top;
        const oldTop = oldState.discard_top;
        const discardChanged = newTop && (!oldTop ||
            oldTop.rank !== newTop.rank ||
            oldTop.suit !== newTop.suit);

        // Find hand changes for the player who just played
        if (turnChanged && previousPlayerId) {
            const oldPlayer = oldState.players.find(p => p.id === previousPlayerId);
            const newPlayer = newState.players.find(p => p.id === previousPlayerId);

            if (oldPlayer && newPlayer) {
                // First pass: detect swaps (card identity changed)
                const swappedPositions = new Set();
                for (let i = 0; i < 6; i++) {
                    const oldCard = oldPlayer.cards[i];
                    const newCard = newPlayer.cards[i];

                    // Card identity changed = swap happened at this position
                    if (this.cardIdentityChanged(oldCard, newCard)) {
                        swappedPositions.add(i);

                        // Use discard_top for the revealed card (more reliable for opponents)
                        const revealedCard = newState.discard_top || { ...oldCard, face_up: true };

                        movements.push({
                            type: 'swap',
                            playerId: previousPlayerId,
                            position: i,
                            oldCard: revealedCard,
                            newCard: newCard
                        });
                        break; // Only one swap per turn
                    }
                }

                // Second pass: detect flips (card went from face_down to face_up, not a swap)
                for (let i = 0; i < 6; i++) {
                    if (swappedPositions.has(i)) continue; // Skip if already detected as swap

                    const oldCard = oldPlayer.cards[i];
                    const newCard = newPlayer.cards[i];

                    if (this.cardWasFlipped(oldCard, newCard)) {
                        movements.push({
                            type: 'flip',
                            playerId: previousPlayerId,
                            position: i,
                            faceUp: true,
                            card: newCard
                        });
                    }
                }
            }
        }

        // Detect drawing (current player just drew)
        if (newState.has_drawn_card && !oldState.has_drawn_card) {
            // Discard pile decreased = drew from discard
            const drewFromDiscard = !newState.discard_top ||
                (oldState.discard_top &&
                 (!newState.discard_top ||
                  oldState.discard_top.rank !== newState.discard_top.rank ||
                  oldState.discard_top.suit !== newState.discard_top.suit));

            movements.push({
                type: drewFromDiscard ? 'draw-discard' : 'draw-deck',
                playerId: currentPlayerId
            });
        }

        return movements;
    }

    // Check if the card identity (rank+suit) changed between old and new
    // Returns true if definitely different cards, false if same or unknown
    cardIdentityChanged(oldCard, newCard) {
        // If both have rank/suit data, compare directly
        if (oldCard.rank && newCard.rank) {
            return oldCard.rank !== newCard.rank || oldCard.suit !== newCard.suit;
        }
        // Can't determine - assume same card (flip, not swap)
        return false;
    }

    // Check if a card was just flipped (same card, now face up)
    cardWasFlipped(oldCard, newCard) {
        return !oldCard.face_up && newCard.face_up;
    }

    // Get a summary of movements for debugging
    summarize(movements) {
        return movements.map(m => {
            switch (m.type) {
                case 'flip':
                    return `Flip: Player ${m.playerId} position ${m.position}`;
                case 'swap':
                    return `Swap: Player ${m.playerId} position ${m.position}`;
                case 'discard':
                    return `Discard: ${m.card.rank}${m.card.suit} from player ${m.fromPlayerId}`;
                case 'draw-deck':
                    return `Draw from deck: Player ${m.playerId}`;
                case 'draw-discard':
                    return `Draw from discard: Player ${m.playerId}`;
                default:
                    return `Unknown: ${m.type}`;
            }
        }).join('\n');
    }
}

// Export for use in app.js
if (typeof module !== 'undefined' && module.exports) {
    module.exports = StateDiffer;
}
