import { useCallback, useEffect, useRef, useState } from 'react';
import './App.css';

const CELL_SIZE = 20;
const DEFAULT_CANVAS_SIZE = 400; // Default canvas size for initial state

const SPECIAL_EVERY = 5;
const SPECIAL_BONUS = 5;
const SPECIAL_DURATION_MS = 5000;

function getSpeedForLevel(level) {
  const clamped = Math.min(5, Math.max(1, level));
  return 170 - (clamped - 1) * 25;
}

export default function App() {
  const canvasRef = useRef(null);
  const containerRef = useRef(null);
  const gameLoopRef = useRef(null);

  const snakeRef = useRef([]);
  const foodRef = useRef({ x: 0, y: 0 });
  const specialFoodRef = useRef(null);
  const specialExpiresAtRef = useRef(0);
  const directionRef = useRef({ dx: 1, dy: 0 });
  const foodsEatenRef = useRef(0);
  const scoreRef = useRef(0);
  const lastProcessedDirectionRef = useRef({ dx: 1, dy: 0 });
  const isPausedRef = useRef(false);

  const [canvasSize, setCanvasSize] = useState(DEFAULT_CANVAS_SIZE);
  const [gridWidth, setGridWidth] = useState(Math.floor(DEFAULT_CANVAS_SIZE / CELL_SIZE));
  const [gridHeight, setGridHeight] = useState(Math.floor(DEFAULT_CANVAS_SIZE / CELL_SIZE));
  
  const [score, setScore] = useState(0);
  const [isPaused, setIsPaused] = useState(false);
  const [highScore, setHighScore] = useState(() => {
    return Number(localStorage.getItem('snakeHighList')) || 0;
  });
  const [level, setLevel] = useState('1');
  const [startTitle, setStartTitle] = useState('Snake Game');
  const [finalScore, setFinalScore] = useState(0);
  const [showStartScreen, setShowStartScreen] = useState(true);
  const [scoreUpdated, setScoreUpdated] = useState(false);
  const [gameOverShake, setGameOverShake] = useState(false);
  const [coinDropping, setCoinDropping] = useState(false);

  // Touch control refs
  const touchStartRef = useRef({ x: 0, y: 0 });
  const touchStartTimeRef = useRef(0);

  const placeFood = useCallback(() => {
    let candidate;
    do {
      candidate = {
        x: Math.floor(Math.random() * gridWidth),
        y: Math.floor(Math.random() * gridHeight),
      };
    } while (
      snakeRef.current.some(
        (segment) => segment.x === candidate.x && segment.y === candidate.y
      ) ||
      (specialFoodRef.current &&
        specialFoodRef.current.x === candidate.x &&
        specialFoodRef.current.y === candidate.y)
    );
    return candidate;
  }, [gridWidth, gridHeight]);

  const placeSpecialFood = useCallback(() => {
    let candidate;
    do {
      candidate = {
        x: Math.floor(Math.random() * gridWidth),
        y: Math.floor(Math.random() * gridHeight),
      };
    } while (
      snakeRef.current.some(
        (segment) => segment.x === candidate.x && segment.y === candidate.y
      ) ||
      (foodRef.current &&
        foodRef.current.x === candidate.x &&
        foodRef.current.y === candidate.y)
    );
    return candidate;
  }, [gridWidth, gridHeight]);

  // CRT-style background with subtle grid
  const drawBackground = useCallback((ctx) => {
    // Dark CRT background
    ctx.fillStyle = '#0a0a12';
    ctx.fillRect(0, 0, canvasSize, canvasSize);
    
    // Subtle grid lines (very faint)
    ctx.strokeStyle = 'rgba(0, 255, 247, 0.03)';
    ctx.lineWidth = 1;
    for (let i = 0; i <= gridWidth; i++) {
      ctx.beginPath();
      ctx.moveTo(i * CELL_SIZE, 0);
      ctx.lineTo(i * CELL_SIZE, canvasSize);
      ctx.stroke();
    }
    for (let i = 0; i <= gridHeight; i++) {
      ctx.beginPath();
      ctx.moveTo(0, i * CELL_SIZE);
      ctx.lineTo(canvasSize, i * CELL_SIZE);
      ctx.stroke();
    }
  }, [canvasSize, gridWidth, gridHeight]);

  // Phosphor green snake with glow
  const drawSnake = useCallback((ctx) => {
    const snake = snakeRef.current;
    const { dx, dy } = directionRef.current;
    
    snake.forEach((segment, index) => {
      const x = segment.x * CELL_SIZE;
      const y = segment.y * CELL_SIZE;
      
      // Glow effect for head
      if (index === 0) {
        ctx.shadowColor = '#00ff00';
        ctx.shadowBlur = 10;
      } else {
        ctx.shadowBlur = 0;
      }
      
      // Phosphor green color - head is brighter
      ctx.fillStyle = index === 0 ? '#00ff00' : '#00cc00';
      ctx.fillRect(x + 1, y + 1, CELL_SIZE - 2, CELL_SIZE - 2);
      
      // Reset shadow
      ctx.shadowBlur = 0;
      
      // Draw eyes on head
      if (index === 0) {
        ctx.fillStyle = '#000';
        let eye1X, eye1Y, eye2X, eye2Y;
        
        if (dx === 1) {
          eye1X = x + 12; eye1Y = y + 5;
          eye2X = x + 12; eye2Y = y + 12;
        } else if (dx === -1) {
          eye1X = x + 5; eye1Y = y + 5;
          eye2X = x + 5; eye2Y = y + 12;
        } else if (dy === 1) {
          eye1X = x + 5; eye1Y = y + 12;
          eye2X = x + 12; eye2Y = y + 12;
        } else {
          eye1X = x + 5; eye1Y = y + 5;
          eye2X = x + 12; eye2Y = y + 5;
        }
        
        ctx.fillRect(eye1X, eye1Y, 3, 3);
        ctx.fillRect(eye2X, eye2Y, 3, 3);
      }
    });
  }, []);

  // Food with neon glow
  const drawFood = useCallback((ctx) => {
    const food = foodRef.current;
    const x = food.x * CELL_SIZE + CELL_SIZE / 2;
    const y = food.y * CELL_SIZE + CELL_SIZE / 2;
    
    // Glow effect
    ctx.shadowColor = '#ff6600';
    ctx.shadowBlur = 15;
    
    ctx.fillStyle = '#ff6600';
    ctx.beginPath();
    ctx.arc(x, y, CELL_SIZE / 2 - 2, 0, Math.PI * 2);
    ctx.fill();
    
    // Reset shadow
    ctx.shadowBlur = 0;
  }, []);

  // Special food with cyan glow
  const drawSpecialFood = useCallback((ctx) => {
    const specialFood = specialFoodRef.current;
    if (!specialFood) return;
    
    const x = specialFood.x * CELL_SIZE + CELL_SIZE / 2;
    const y = specialFood.y * CELL_SIZE + CELL_SIZE / 2;
    
    // Pulsing glow effect
    const pulse = Math.sin(Date.now() / 100) * 0.3 + 0.7;
    ctx.shadowColor = '#00fff7';
    ctx.shadowBlur = 20 * pulse;
    
    ctx.fillStyle = '#00fff7';
    ctx.beginPath();
    ctx.arc(x, y, CELL_SIZE / 2 - 2, 0, Math.PI * 2);
    ctx.fill();
    
    // Reset shadow
    ctx.shadowBlur = 0;
  }, []);

  const drawFrame = useCallback(() => {
    const canvas = canvasRef.current;
    if (!canvas) return;

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

    drawBackground(ctx);
    drawFood(ctx);
    drawSpecialFood(ctx);
    drawSnake(ctx);
  }, [drawBackground, drawFood, drawSnake, drawSpecialFood]);

  const resetGame = useCallback(() => {
    const startX = Math.floor(gridWidth / 2);
    const startY = Math.floor(gridHeight / 2);

    snakeRef.current = [
      { x: startX, y: startY },
      { x: startX - 1, y: startY },
      { x: startX - 2, y: startY },
    ];

    directionRef.current = { dx: 1, dy: 0 };
    lastProcessedDirectionRef.current = { dx: 1, dy: 0 };
    scoreRef.current = 0;
    foodsEatenRef.current = 0;
    specialFoodRef.current = null;
    specialExpiresAtRef.current = 0;

    setScore(0);
    setScoreUpdated(false);
    foodRef.current = placeFood();
    drawFrame();
  }, [drawFrame, placeFood, gridWidth, gridHeight]);

  const endGame = useCallback(() => {
    if (gameLoopRef.current !== null) {
      clearInterval(gameLoopRef.current);
      gameLoopRef.current = null;
    }

    setGameOverShake(true);
    setTimeout(() => setGameOverShake(false), 500);

    setStartTitle('Game Over');
    setFinalScore(scoreRef.current);
    if (scoreRef.current > highScore) {
      setHighScore(scoreRef.current);
      localStorage.setItem('snakeHighList', scoreRef.current);
    }
    setShowStartScreen(true);
  }, [highScore]);

  const update = useCallback(() => {
    if (isPausedRef.current) return;
    const snake = snakeRef.current;
    const { dx, dy } = directionRef.current;

    if (snake.length === 0) return;

    lastProcessedDirectionRef.current = directionRef.current;

    const head = { x: snake[0].x + dx, y: snake[0].y + dy };

    if (
      specialFoodRef.current &&
      Date.now() > specialExpiresAtRef.current
    ) {
      specialFoodRef.current = null;
      specialExpiresAtRef.current = 0;
    }

    if (head.x < 0 || head.x >= gridWidth || head.y < 0 || head.y >= gridHeight) {
      endGame();
      return;
    }

    if (snake.some((segment) => segment.x === head.x && segment.y === head.y)) {
      endGame();
      return;
    }

    snake.unshift(head);

    if (head.x === foodRef.current.x && head.y === foodRef.current.y) {
      scoreRef.current += 1;
      foodsEatenRef.current += 1;
      setScore(scoreRef.current);
      setScoreUpdated(true);
      setTimeout(() => setScoreUpdated(false), 300);
      
      foodRef.current = placeFood();

      if (foodsEatenRef.current % SPECIAL_EVERY === 0) {
        specialFoodRef.current = placeSpecialFood();
        specialExpiresAtRef.current = Date.now() + SPECIAL_DURATION_MS;
      }
    } else {
      snake.pop();
    }

    if (
      specialFoodRef.current &&
      head.x === specialFoodRef.current.x &&
      head.y === specialFoodRef.current.y
    ) {
      scoreRef.current += SPECIAL_BONUS;
      setScore(scoreRef.current);
      setScoreUpdated(true);
      setTimeout(() => setScoreUpdated(false), 300);
      
      specialFoodRef.current = null;
      specialExpiresAtRef.current = 0;
    }

    drawFrame();
  }, [drawFrame, endGame, placeFood, placeSpecialFood, gridWidth, gridHeight]);

  const startGame = useCallback(() => {
    if (gameLoopRef.current !== null) {
      clearInterval(gameLoopRef.current);
    }

    setStartTitle('Snake Game');
    setFinalScore(0);
    resetGame();
    isPausedRef.current = false;
    setIsPaused(false);

    const speed = getSpeedForLevel(Number(level));
    gameLoopRef.current = setInterval(update, speed);
    setShowStartScreen(false);
  }, [level, resetGame, update]);

  // Coin slot animation
  const handleCoinClick = useCallback(() => {
    if (coinDropping) return;
    setCoinDropping(true);
    setTimeout(() => setCoinDropping(false), 600);
  }, [coinDropping]);

  // Handle canvas resize based on container
  useEffect(() => {
    const updateCanvasSize = () => {
      if (containerRef.current) {
        const containerWidth = containerRef.current.clientWidth;
        const containerHeight = containerRef.current.clientHeight;
        
        // Use the smaller dimension to maintain square aspect ratio
        // but maximize the use of available space
        const size = Math.min(containerWidth, containerHeight);
        
        // Round down to nearest multiple of CELL_SIZE for clean grid
        const roundedSize = Math.floor(size / CELL_SIZE) * CELL_SIZE;
        
        // Ensure minimum size (10 cells)
        const newSize = Math.max(roundedSize, CELL_SIZE * 10);
        
        setCanvasSize(prevSize => {
          if (prevSize !== newSize) {
            // Grid dimensions changed - reset game state to prevent out-of-bounds issues
            const newGridWidth = Math.floor(newSize / CELL_SIZE);
            const newGridHeight = Math.floor(newSize / CELL_SIZE);
            
            // Reposition snake to center of new grid if it's outside bounds
            const snake = snakeRef.current;
            if (snake.length > 0) {
              const maxX = newGridWidth - 1;
              const maxY = newGridHeight - 1;
              const head = snake[0];
              
              // Check if snake head is out of bounds
              if (head.x > maxX || head.y > maxY) {
                // Reset snake to center of new grid
                const startX = Math.floor(newGridWidth / 2);
                const startY = Math.floor(newGridHeight / 2);
                snakeRef.current = [
                  { x: startX, y: startY },
                  { x: startX - 1, y: startY },
                  { x: startX - 2, y: startY },
                ];
                directionRef.current = { dx: 1, dy: 0 };
                lastProcessedDirectionRef.current = { dx: 1, dy: 0 };
              }
            }
            
            // Reposition food if out of bounds
            if (foodRef.current.x >= newGridWidth || foodRef.current.y >= newGridHeight) {
              foodRef.current = {
                x: Math.floor(Math.random() * newGridWidth),
                y: Math.floor(Math.random() * newGridHeight),
              };
            }
            
            // Remove special food if out of bounds
            if (specialFoodRef.current &&
                (specialFoodRef.current.x >= newGridWidth || specialFoodRef.current.y >= newGridHeight)) {
              specialFoodRef.current = null;
              specialExpiresAtRef.current = 0;
            }
            
            setGridWidth(newGridWidth);
            setGridHeight(newGridHeight);
          }
          return newSize;
        });
      }
    };

    // Initial size calculation with a small delay to ensure container is rendered
    const initialTimer = setTimeout(updateCanvasSize, 100);

    // Use ResizeObserver for more accurate container size detection
    const resizeObserver = new ResizeObserver(() => {
      updateCanvasSize();
    });

    if (containerRef.current) {
      resizeObserver.observe(containerRef.current);
    }

    // Also update on window resize
    window.addEventListener('resize', updateCanvasSize);
    
    return () => {
      clearTimeout(initialTimer);
      resizeObserver.disconnect();
      window.removeEventListener('resize', updateCanvasSize);
    };
  }, []);

  useEffect(() => {
    resetGame();

    return () => {
      if (gameLoopRef.current !== null) {
        clearInterval(gameLoopRef.current);
      }
    };
  }, [resetGame]);

  useEffect(() => {
    const onKeyDown = (event) => {
      const key = event.key.toLowerCase();
      const { dx, dy } = lastProcessedDirectionRef.current;

      switch (key) {
        case 'arrowup':
        case 'w':
          if (dy === 0) {
            directionRef.current = { dx: 0, dy: -1 };
          }
          event.preventDefault();
          break;
        case 'arrowdown':
        case 's':
          if (dy === 0) {
            directionRef.current = { dx: 0, dy: 1 };
          }
          event.preventDefault();
          break;
        case 'arrowleft':
        case 'a':
          if (dx === 0) {
            directionRef.current = { dx: -1, dy: 0 };
          }
          event.preventDefault();
          break;
        case 'arrowright':
        case 'd':
          if (dx === 0) {
            directionRef.current = { dx: 1, dy: 0 };
          }
          event.preventDefault();
          break;
        case ' ':
        case 'escape':
          if (gameLoopRef.current) {
            isPausedRef.current = !isPausedRef.current;
            setIsPaused((prev) => !prev);
            event.preventDefault();
          }
          break;
        default:
          break;
      }
    };

    window.addEventListener('keydown', onKeyDown);
    return () => window.removeEventListener('keydown', onKeyDown);
  }, []);

  // Touch swipe handling
  const handleTouchStart = useCallback((e) => {
    const touch = e.touches[0];
    touchStartRef.current = { x: touch.clientX, y: touch.clientY };
    touchStartTimeRef.current = Date.now();
  }, []);

  const handleTouchMove = useCallback((e) => {
    e.preventDefault();
  }, []);

  const handleTouchEnd = useCallback((e) => {
    const touch = e.changedTouches[0];
    const dx = touch.clientX - touchStartRef.current.x;
    const dy = touch.clientY - touchStartRef.current.y;
    const touchDuration = Date.now() - touchStartTimeRef.current;
    
    const minSwipeDistance = 30;
    const maxTouchDuration = 300;
    
    if (Math.abs(dx) < minSwipeDistance && Math.abs(dy) < minSwipeDistance) return;
    if (touchDuration > maxTouchDuration) return;
    
    const lastDir = lastProcessedDirectionRef.current;
    
    if (Math.abs(dx) > Math.abs(dy)) {
      if (dx > 0 && lastDir.dx === 0) {
        directionRef.current = { dx: 1, dy: 0 };
      } else if (dx < 0 && lastDir.dx === 0) {
        directionRef.current = { dx: -1, dy: 0 };
      }
    } else {
      if (dy > 0 && lastDir.dy === 0) {
        directionRef.current = { dx: 0, dy: 1 };
      } else if (dy < 0 && lastDir.dy === 0) {
        directionRef.current = { dx: 0, dy: -1 };
      }
    }
  }, []);

  // Direction button handler for on-screen controls
  const handleDirectionButton = useCallback((dx, dy) => {
    const lastDir = lastProcessedDirectionRef.current;
    
    if (dx !== 0 && lastDir.dx === 0) {
      directionRef.current = { dx, dy: 0 };
    } else if (dy !== 0 && lastDir.dy === 0) {
      directionRef.current = { dx: 0, dy };
    }
  }, []);

  return (
    <main className="arcade-cabinet">
      <div className="cabinet-inner">
        {/* Marquee Area */}
        <header className="marquee">
          <h1 className="marquee-title">Snake Reactor</h1>
          <p className="marquee-subtitle">Arcade Edition</p>
        </header>

        {/* Decorative Rivets */}
        <div className="rivets-row">
          <div className="rivet"></div>
          <div className="rivet"></div>
          <div className="rivet"></div>
        </div>

        {/* LED Score Display */}
        <div className="led-display-panel">
          <div className="led-display">
            <span className="led-label">Score</span>
            <span className="led-value">{String(score).padStart(4, '0')}</span>
          </div>
          <div className="led-display">
            <span className="led-label">Level</span>
            <span className="led-value highlight">{level}</span>
          </div>
          <div className="led-display">
            <span className="led-label">High</span>
            <span className="led-value">{String(Math.max(score, highScore)).padStart(4, '0')}</span>
          </div>
        </div>

        {/* CRT Screen Area */}
        <section className={`screen-bezel ${gameOverShake ? 'game-over-shake' : ''}`}>
          <div ref={containerRef} className="crt-screen">
            {showStartScreen && (
              <div className="game-overlay">
                <h2 className={startTitle === 'Game Over' ? 'game-over' : ''}>{startTitle}</h2>
                {startTitle === 'Game Over' && (
                  <div className="final-score-box">
                    <p className="final-score">Score: {finalScore}</p>
                    {finalScore >= highScore && finalScore > 0 && (
                      <p className="new-high-score">New High Score!</p>
                    )}
                  </div>
                )}
                <label htmlFor="levelSelect">Select Level</label>
                <select
                  id="levelSelect"
                  className="level-select"
                  value={level}
                  onChange={(event) => setLevel(event.target.value)}
                >
                  <option value="1">Level 1 - Slow</option>
                  <option value="2">Level 2</option>
                  <option value="3">Level 3</option>
                  <option value="4">Level 4</option>
                  <option value="5">Level 5 - Fast</option>
                </select>
                <button type="button" className="start-btn" onClick={startGame}>
                  Start Game
                </button>
              </div>
            )}
            {isPaused && !showStartScreen && (
              <div className="game-overlay">
                <h2>Paused</h2>
                <button
                  type="button"
                  className="start-btn"
                  onClick={() => {
                    isPausedRef.current = false;
                    setIsPaused(false);
                  }}
                >
                  Resume
                </button>
              </div>
            )}
            <canvas
              ref={canvasRef}
              width={canvasSize}
              height={canvasSize}
              onTouchStart={handleTouchStart}
              onTouchMove={handleTouchMove}
              onTouchEnd={handleTouchEnd}
            />
          </div>
        </section>

        {/* Control Panel */}
        <div className="control-panel">
          {/* Coin Slot */}
          <div className="coin-slot-area">
            <div className="coin-slot">
              <span className="coin-slot-label">Insert Coin</span>
              <div
                className={`coin-slot-opening ${coinDropping ? 'dropping' : ''}`}
                onClick={handleCoinClick}
              >
                <div className="coin"></div>
              </div>
            </div>

            {/* Power Switch */}
            <div className="power-switch-container">
              <span className="power-switch-label">Power</span>
              <div className="power-switch"></div>
            </div>

            {/* Volume Knob */}
            <div className="volume-control">
              <div className="volume-knob"></div>
              <span className="volume-knob-label">Volume</span>
            </div>
          </div>

          {/* LED Indicators */}
          <div className="led-indicator-row">
            <div className="led-indicator"></div>
            <div className="led-indicator green"></div>
            <div className="led-indicator yellow"></div>
          </div>

          {/* Start Button */}
          {!showStartScreen && (
            <div className="pause-btn-container">
              <button
                type="button"
                className="start-btn"
                onClick={() => {
                  isPausedRef.current = !isPausedRef.current;
                  setIsPaused((prev) => !prev);
                }}
              >
                {isPaused ? 'Resume' : 'Pause'}
              </button>
            </div>
          )}

          {/* Direction Controls */}
          <div className="direction-controls">
            <div className="arcade-btn-bezel">
              <button
                type="button"
                className="arcade-btn red"
                onPointerDown={() => handleDirectionButton(0, -1)}
                aria-label="Move up"
              >
                ▲
              </button>
            </div>
            <div className="control-row">
              <div className="arcade-btn-bezel">
                <button
                  type="button"
                  className="arcade-btn yellow"
                  onPointerDown={() => handleDirectionButton(-1, 0)}
                  aria-label="Move left"
                >
                  ◀
                </button>
              </div>
              <div className="arcade-btn-bezel">
                <button
                  type="button"
                  className="arcade-btn red"
                  onPointerDown={() => handleDirectionButton(0, 1)}
                  aria-label="Move down"
                >
                  ▼
                </button>
              </div>
              <div className="arcade-btn-bezel">
                <button
                  type="button"
                  className="arcade-btn yellow"
                  onPointerDown={() => handleDirectionButton(1, 0)}
                  aria-label="Move right"
                >
                  ▶
                </button>
              </div>
            </div>
          </div>
        </div>

        {/* Brand Plaque */}
        <div className="brand-plaque">
          <span className="brand-plaque-text">ARCADE SYSTEMS © 1985</span>
        </div>

        {/* Speaker Grille */}
        <div className="speaker-grille">
          <div className="speaker-holes">
            {[...Array(24)].map((_, i) => (
              <div key={i} className="speaker-hole"></div>
            ))}
          </div>
        </div>

        {/* Cabinet Vents */}
        <div className="cabinet-vents">
          <div className="vent-slot"></div>
          <div className="vent-slot"></div>
          <div className="vent-slot"></div>
        </div>

        {/* Cabinet Screws */}
        <div className="cabinet-screws">
          <div className="screw"></div>
          <div className="screw"></div>
        </div>
      </div>
    </main>
  );
}
