import { useRef, useEffect, useState } from 'react';
import type { GameState } from '../../lib/snakeAI/game';
import { createGame, step, getInputs } from '../../lib/snakeAI/game';
import { getAction, type Network } from '../../lib/snakeAI/network';

interface SnakeCanvasProps {
    network: Network | null;
    gridSize: number;
    showGrid?: boolean;
    size?: 'small' | 'normal' | 'large';
    showStats?: boolean; // Show score/length/steps even in small mode
    playbackSpeed?: number; // Steps per second (default: 15)
}

const CELL_SIZES = {
    small: 8,
    normal: 20,
    large: 30,
};

const CANVAS_PADDING = 10;

export default function SnakeCanvas({ network, gridSize, showGrid = true, size = 'normal', showStats = false, playbackSpeed = 15 }: SnakeCanvasProps) {
    const canvasRef = useRef<HTMLCanvasElement>(null);
    const [currentGame, setCurrentGame] = useState<GameState | null>(null);
    const animationFrameRef = useRef<number>();
    const lastUpdateRef = useRef<number>(0);
    const networkRef = useRef(network);

    useEffect(() => {
        networkRef.current = network;
    }, [network]);

    const CELL_SIZE = CELL_SIZES[size];

    // Initialize game when network or gridSize changes
    useEffect(() => {
        if (network) {
            setCurrentGame(createGame(gridSize));
        }
    }, [network?.id, gridSize]);

    // Animation loop to step through game
    useEffect(() => {
        if (!network || !currentGame) return;

        const STEPS_PER_SECOND = playbackSpeed; // Use prop
        const UPDATE_INTERVAL = 1000 / STEPS_PER_SECOND;

        const animate = (timestamp: number) => {
            const elapsed = timestamp - lastUpdateRef.current;

            if (elapsed >= UPDATE_INTERVAL) {
                setCurrentGame((prevGame) => {
                    if (!prevGame) return prevGame;

                    // If game is over, start a new one
                    if (!prevGame.alive) {
                        return createGame(gridSize);
                    }

                    // Get neural network decision
                    const currentNetwork = networkRef.current;
                    if (!currentNetwork) return prevGame;

                    const inputs = getInputs(prevGame);
                    const action = getAction(currentNetwork, inputs);

                    // Step the game forward
                    return step(prevGame, action);
                });

                lastUpdateRef.current = timestamp;
            }

            animationFrameRef.current = requestAnimationFrame(animate);
        };

        animationFrameRef.current = requestAnimationFrame(animate);

        return () => {
            if (animationFrameRef.current) {
                cancelAnimationFrame(animationFrameRef.current);
            }
        };
    }, [network?.id, !!currentGame, gridSize, playbackSpeed]); // Added playbackSpeed dependency

    // Set canvas size once when props change (not on every render)
    useEffect(() => {
        if (!canvasRef.current) return;
        const canvas = canvasRef.current;
        const canvasSize = gridSize * CELL_SIZE + CANVAS_PADDING * 2;
        canvas.width = canvasSize;
        canvas.height = canvasSize;
    }, [gridSize, size]);

    // Render game to canvas
    useEffect(() => {
        if (!currentGame || !canvasRef.current) return;

        const canvas = canvasRef.current;
        const ctx = canvas.getContext('2d');
        if (!ctx) return;

        const canvasSize = gridSize * CELL_SIZE + CANVAS_PADDING * 2;

        // Clear canvas
        ctx.fillStyle = '#000000';
        ctx.fillRect(0, 0, canvasSize, canvasSize);

        // Draw grid
        if (showGrid) {
            ctx.strokeStyle = '#1a1a1a';
            ctx.lineWidth = 1;
            for (let i = 0; i <= currentGame.gridSize; i++) {
                const pos = i * CELL_SIZE + CANVAS_PADDING;
                ctx.beginPath();
                ctx.moveTo(pos, CANVAS_PADDING);
                ctx.lineTo(pos, currentGame.gridSize * CELL_SIZE + CANVAS_PADDING);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(CANVAS_PADDING, pos);
                ctx.lineTo(currentGame.gridSize * CELL_SIZE + CANVAS_PADDING, pos);
                ctx.stroke();
            }
        }

        // Draw food
        ctx.fillStyle = '#ff6b6b';
        ctx.shadowBlur = 15;
        ctx.shadowColor = '#ff6b6b';
        const foodX = currentGame.food.x * CELL_SIZE + CANVAS_PADDING + CELL_SIZE / 2;
        const foodY = currentGame.food.y * CELL_SIZE + CANVAS_PADDING + CELL_SIZE / 2;
        ctx.beginPath();
        ctx.arc(foodX, foodY, CELL_SIZE / 3, 0, Math.PI * 2);
        ctx.fill();
        ctx.shadowBlur = 0;

        // Draw snake
        currentGame.snake.forEach((segment, index) => {
            const x = segment.x * CELL_SIZE + CANVAS_PADDING;
            const y = segment.y * CELL_SIZE + CANVAS_PADDING;

            if (index === 0) {
                // Head - brighter and larger
                ctx.fillStyle = currentGame.alive ? '#4ecdc4' : '#e74c3c';
                ctx.shadowBlur = 10;
                ctx.shadowColor = currentGame.alive ? '#4ecdc4' : '#e74c3c';
            } else {
                // Body - gradient from head to tail
                const alpha = 1 - (index / currentGame.snake.length) * 0.5;
                ctx.fillStyle = `rgba(78, 205, 196, ${alpha})`;
                ctx.shadowBlur = 0;
            }

            ctx.fillRect(x + 2, y + 2, CELL_SIZE - 4, CELL_SIZE - 4);
        });

        ctx.shadowBlur = 0;

        // Draw death overlay if dead
        if (!currentGame.alive) {
            ctx.fillStyle = 'rgba(231, 76, 60, 0.2)';
            ctx.fillRect(0, 0, canvasSize, canvasSize);

            ctx.fillStyle = '#e74c3c';
            ctx.font = `bold ${size === 'small' ? '16' : '24'}px 'Courier New', monospace`;
            ctx.textAlign = 'center';
            ctx.textBaseline = 'middle';
            ctx.fillText('DEAD', canvasSize / 2, canvasSize / 2);
        }
    }, [currentGame, showGrid]);

    // Calculate canvas size from props, not state, to prevent shaking
    const canvasSize = gridSize * CELL_SIZE + CANVAS_PADDING * 2;

    return (
        <div className="snake-canvas-container">
            <canvas
                ref={canvasRef}
                width={canvasSize}
                height={canvasSize}
                style={{
                    width: `${canvasSize}px`,
                    height: `${canvasSize}px`,
                    border: '1px solid #333',
                    backgroundColor: '#000000',
                }}
            />
            {currentGame && (size !== 'small' || showStats) && (
                <div className="canvas-info" style={size === 'small' ? { fontSize: '0.7rem', gap: '0.5rem', padding: '0.4rem 0.8rem' } : {}}>
                    <div className="info-item">
                        <span className="label">Score:</span>
                        <span className="value" style={{ fontVariantNumeric: 'tabular-nums', minWidth: '2ch', display: 'inline-block' }}>{currentGame.score}</span>
                    </div>
                    <div className="info-item">
                        <span className="label">Steps:</span>
                        <span className="value" style={{ fontVariantNumeric: 'tabular-nums', minWidth: '3ch', display: 'inline-block' }}>{currentGame.steps}</span>
                    </div>
                </div>
            )}
        </div>
    );
}
