/**
 * @typedef {Object} Card
 * @property {number} x
 * @property {number} y
 * @property {CardData} card
 * @property {boolean} isFaceUp
 */

/**
 * @typedef {Object} CardData
 * @property {string} suit
 * @property {string} value
 */

/**
 * @typedef {Object} GameState
 * @property {Card[]} cards
 * @property {Card|null} draggingCard
 * @property {CardData[]} deck
 * @property {{x: number, y: number}} stackPosition
 */

// Constants
const CARD_WIDTH = 100;
const CARD_HEIGHT = 150;
const PADDING = 10;
const SUITS = ['❤️', '♦️', '♣️', '♠️'];
const VALUES = ['2', '3', '4', '5', '6', '7', '8', '9', '10', 'J', 'Q', 'K', 'A'];
const PATTERN_SIZE = 10;
const INITIAL_CARD_X = 20;
const INITIAL_CARD_Y = 20;
const FONT_SIZE = '34px "pokemon-font", monospace';
const CARD_BORDER_COLOR = '#000000';
const CARD_FACE_COLOR = '#FFFFFF';

// Canvas setup
const canvas = document.getElementById('cards');
const ctx = canvas.getContext('2d');
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;

// Pure functions
const shuffle = array => {
    const result = [...array];
    for (let i = result.length - 1; i > 0; i--) {
        const j = Math.floor(Math.random() * (i + 1));
        [result[i], result[j]] = [result[j], result[i]];
    }
    return result;
};

const createDeck = () => SUITS.flatMap(suit => VALUES.map(value => ({ suit, value })));

// Create a more functional card factory
const createCard = (x, y, cardData) => Object.freeze({
    x: x + PADDING,
    y: y + PADDING,
    card: Object.freeze({ ...cardData }),
    isFaceUp: false
});

// Function to check if a point is within a card
const isPointInCard = (x, y, card) =>
    x >= card.x && x <= card.x + CARD_WIDTH && y >= card.y && y <= card.y + CARD_HEIGHT;

// Rendering functions
const clearCanvas = () => {
    ctx.fillStyle = 'beige';
    ctx.fillRect(0, 0, canvas.width, canvas.height);
};

const drawCardBack = card => {
    ctx.fillRect(card.x, card.y, CARD_WIDTH, CARD_HEIGHT);
    drawRetroPattern(card);
    ctx.strokeStyle = CARD_BORDER_COLOR;
    ctx.strokeRect(card.x, card.y, CARD_WIDTH, CARD_HEIGHT);
};

const drawRetroPattern = card => {
    const checkeredSize = 10; // Size of each square in the checkered pattern
    for (let i = 0; i < CARD_WIDTH; i += checkeredSize) {
        for (let j = 0; j < CARD_HEIGHT; j += checkeredSize) {
            // Alternate colors for the checkered pattern
            ctx.fillStyle = (Math.floor(i / checkeredSize) + Math.floor(j / checkeredSize)) % 2 === 0 ? '#FF9900' : '#FFCC00';
            ctx.fillRect(card.x + i, card.y + j, checkeredSize, checkeredSize);
        }
    }
};

const drawCardFront = card => {
    ctx.fillStyle = CARD_FACE_COLOR;
    ctx.fillRect(card.x, card.y, CARD_WIDTH, CARD_HEIGHT);
    ctx.fillStyle = CARD_BORDER_COLOR;
    ctx.font = FONT_SIZE;
    ctx.strokeRect(card.x, card.y, CARD_WIDTH, CARD_HEIGHT);
    
    // Draw value and suit with a retro font style
    drawCardValue(card.card.value, card.x + 12, card.y + 42, 'left');
    drawCardSuit(card.card.suit, card.x + CARD_WIDTH / 2, card.y + CARD_HEIGHT / 2 + 20);
};

const drawCardValue = (value, x, y, alignment) => {
    ctx.textAlign = alignment;
    ctx.fillStyle = CARD_BORDER_COLOR;
    ctx.fillText(value, x, y);
};

const drawCardSuit = (suit, x, y) => {
    ctx.textAlign = 'center';
    ctx.fillStyle = CARD_BORDER_COLOR;
    ctx.fillText(suit, x, y);
};

const renderCard = card => {
    card.isFaceUp ? drawCardFront(card) : drawCardBack(card);
};

const renderAllCards = cards => {
    clearCanvas();
    cards.forEach(renderCard); // Renders cards in the order they are in the array
};

// State management
let gameState;

const initializeGameState = () => ({
    cards: [],
    draggingCard: null,
    deck: shuffle(createDeck()),
    stackPosition: { x: 0, y: 0 }
});

const initializeGame = () => {
    try {
        gameState = initializeGameState();
        gameState.cards = gameState.deck.map((cardData, index) => 
            createCard(INITIAL_CARD_X, INITIAL_CARD_Y + index * 5, cardData)
        );

        clearCanvas();
        renderAllCards(gameState.cards);
        
        setupEventListeners();
    } catch (error) {
        console.error('Failed to initialize game:', error);
        alert('Failed to initialize game. Please refresh the page.');
    }
};

const setupEventListeners = () => {
    canvas.addEventListener('mousedown', handleMouseDown);
    canvas.addEventListener('contextmenu', e => e.preventDefault());
    document.addEventListener('keydown', e => {
        if (e.key === 'q') handleResetGame();
    });
};

// Event handlers
const handleMouseMove = e => {
    if (!gameState.draggingCard) return;

    const rect = canvas.getBoundingClientRect();
    const newX = e.clientX - rect.left - dragOffset.x;
    const newY = e.clientY - rect.top - dragOffset.y;

    // Update the card's position immutably
    const updatedCard = moveCard(gameState.draggingCard, newX, newY);
    gameState.cards = gameState.cards.map(card => 
        card === gameState.draggingCard ? updatedCard : card
    );
    gameState.draggingCard = updatedCard;

    renderAllCards(gameState.cards);
};

const handleMouseUp = e => {
    if (!gameState.draggingCard) {
        const rect = canvas.getBoundingClientRect();
        const x = e.clientX - rect.left;
        const y = e.clientY - rect.top;

        // Check if a card was clicked
        const clickedCard = gameState.cards.slice().reverse().find(card => isPointInCard(x, y, card));
        if (clickedCard) {
            // Move the clicked card to the top of the stack
            gameState.cards = gameState.cards.filter(card => card !== clickedCard);
            gameState.cards.push(clickedCard);
            renderAllCards(gameState.cards); // Re-render all cards
        }
    }

    gameState.draggingCard = null;
    document.removeEventListener('mousemove', handleMouseMove);
    document.removeEventListener('mouseup', handleMouseUp);
};

let dragOffset = { x: 0, y: 0 }; // To store the offset of the click position

const findClickedCard = (x, y, cards) => 
    cards.slice().reverse().find(card => isPointInCard(x, y, card));

const moveCardToTop = (targetCard, cards) => [
    ...cards.filter(card => card !== targetCard),
    targetCard
];

const handleMouseDown = e => {
    const rect = canvas.getBoundingClientRect();
    const x = e.clientX - rect.left;
    const y = e.clientY - rect.top;

    if (e.button === 2) {
        e.preventDefault();
        const clickedCard = findClickedCard(x, y, gameState.cards);
        if (clickedCard) {
            const updatedCard = toggleCardFace(clickedCard);
            gameState.cards = gameState.cards.map(card => 
                card === clickedCard ? updatedCard : card
            );
            renderAllCards(gameState.cards);
        }
        return;
    }

    const clickedCard = findClickedCard(x, y, gameState.cards);
    if (clickedCard) {
        gameState.draggingCard = clickedCard;
        dragOffset = {
            x: x - clickedCard.x,
            y: y - clickedCard.y
        };
        gameState.cards = moveCardToTop(clickedCard, gameState.cards);
        
        document.addEventListener('mousemove', handleMouseMove);
        document.addEventListener('mouseup', handleMouseUp);
    }
};

// Add this function to handle the reset confirmation
const handleResetGame = () => {
    if (confirm("Would you like to reset the cards?")) {
        initializeGame(); // Reset the game state
    }
};

const moveCard = (card, newX, newY) => ({
    ...card,
    x: newX,
    y: newY
});

const toggleCardFace = card => ({
    ...card,
    isFaceUp: !card.isFaceUp
});

// Start the game
initializeGame();

// Clean up on window unload
window.addEventListener('unload', () => {
    canvas.removeEventListener('mousedown', handleMouseDown);
    canvas.removeEventListener('contextmenu', e => e.preventDefault());
});