// Conway's Game of Life - Interactive simulation page
const ConwaysGameOfLife = () => {
  const {
    Box, Typography, Paper, Slider, Button, Container, ButtonGroup, Tooltip
  } = MaterialUI;

  const CANVAS_WIDTH = 800;
  const CANVAS_HEIGHT = 500;
  const RANDOM_FILL_PROBABILITY = 0.3;

  const canvasRef = React.useRef(null);
  const cellGridRef = React.useRef(null);
  const playingRef = React.useRef(false);
  const rafRef = React.useRef(null);
  const lastTickRef = React.useRef(0);

  const [rows, setRows] = React.useState(50);
  const [cols, setCols] = React.useState(80);
  const [playing, setPlaying] = React.useState(false);
  const [generation, setGeneration] = React.useState(0);
  const [speed, setSpeed] = React.useState(10); // generations per second
  const [liveCells, setLiveCells] = React.useState(0);

  // Mouse interaction state
  const drawingRef = React.useRef(false);
  const drawModeRef = React.useRef(null); // 'birth' or 'kill'

  // ---------- Grid helpers ----------
  const makeGrid = (r, c) => {
    const g = new Uint8Array(r * c);
    return g;
  };

  const countNeighbors = (grid, r, c, numRows, numCols) => {
    let count = 0;
    for (let dr = -1; dr <= 1; dr++) {
      for (let dc = -1; dc <= 1; dc++) {
        if (dr === 0 && dc === 0) continue;
        const nr = r + dr;
        const nc = c + dc;
        if (nr >= 0 && nr < numRows && nc >= 0 && nc < numCols) {
          count += grid[nr * numCols + nc];
        }
      }
    }
    return count;
  };

  const stepGrid = (grid, numRows, numCols) => {
    const next = new Uint8Array(numRows * numCols);
    for (let r = 0; r < numRows; r++) {
      for (let c = 0; c < numCols; c++) {
        const idx = r * numCols + c;
        const n = countNeighbors(grid, r, c, numRows, numCols);
        if (grid[idx]) {
          next[idx] = (n === 2 || n === 3) ? 1 : 0;
        } else {
          next[idx] = (n === 3) ? 1 : 0;
        }
      }
    }
    return next;
  };

  const countLive = (grid) => {
    let count = 0;
    for (let i = 0; i < grid.length; i++) count += grid[i];
    return count;
  };

  // ---------- Rendering ----------
  const drawGrid = React.useCallback((grid, numRows, numCols) => {
    const canvas = canvasRef.current;
    if (!canvas) return;
    const ctx = canvas.getContext('2d');
    const cellW = canvas.width / numCols;
    const cellH = canvas.height / numRows;

    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Draw live cells
    ctx.fillStyle = '#4caf50';
    for (let r = 0; r < numRows; r++) {
      for (let c = 0; c < numCols; c++) {
        if (grid[r * numCols + c]) {
          ctx.fillRect(c * cellW, r * cellH, cellW, cellH);
        }
      }
    }

    // Draw grid lines
    ctx.strokeStyle = 'rgba(128,128,128,0.25)';
    ctx.lineWidth = 0.5;
    for (let r = 0; r <= numRows; r++) {
      ctx.beginPath();
      ctx.moveTo(0, r * cellH);
      ctx.lineTo(canvas.width, r * cellH);
      ctx.stroke();
    }
    for (let c = 0; c <= numCols; c++) {
      ctx.beginPath();
      ctx.moveTo(c * cellW, 0);
      ctx.lineTo(c * cellW, canvas.height);
      ctx.stroke();
    }
  }, []);

  // ---------- Initialization ----------
  const initGrid = React.useCallback((numRows, numCols) => {
    const grid = makeGrid(numRows, numCols);
    cellGridRef.current = grid;
    setGeneration(0);
    setLiveCells(0);
    drawGrid(grid, numRows, numCols);
  }, [drawGrid]);

  React.useEffect(() => {
    initGrid(rows, cols);
    return () => {
      if (rafRef.current) cancelAnimationFrame(rafRef.current);
    };
  }, [rows, cols, initGrid]);

  // ---------- Animation loop ----------
  React.useEffect(() => {
    playingRef.current = playing;

    if (!playing) {
      if (rafRef.current) {
        cancelAnimationFrame(rafRef.current);
        rafRef.current = null;
      }
      return;
    }

    const tick = (timestamp) => {
      if (!playingRef.current) return;
      const interval = 1000 / speed;
      if (timestamp - lastTickRef.current >= interval) {
        lastTickRef.current = timestamp;
        const grid = cellGridRef.current;
        const next = stepGrid(grid, rows, cols);
        cellGridRef.current = next;
        setGeneration(g => g + 1);
        setLiveCells(countLive(next));
        drawGrid(next, rows, cols);
      }
      rafRef.current = requestAnimationFrame(tick);
    };

    lastTickRef.current = performance.now();
    rafRef.current = requestAnimationFrame(tick);

    return () => {
      if (rafRef.current) {
        cancelAnimationFrame(rafRef.current);
        rafRef.current = null;
      }
    };
  }, [playing, speed, rows, cols, drawGrid]);

  // ---------- Mouse interaction ----------
  const getCellFromEvent = (e) => {
    const canvas = canvasRef.current;
    if (!canvas) return null;
    const rect = canvas.getBoundingClientRect();
    const scaleX = canvas.width / rect.width;
    const scaleY = canvas.height / rect.height;
    const x = (e.clientX - rect.left) * scaleX;
    const y = (e.clientY - rect.top) * scaleY;
    const cellW = canvas.width / cols;
    const cellH = canvas.height / rows;
    const c = Math.floor(x / cellW);
    const r = Math.floor(y / cellH);
    if (r >= 0 && r < rows && c >= 0 && c < cols) return { r, c };
    return null;
  };

  const toggleCell = (r, c) => {
    const grid = cellGridRef.current;
    if (!grid) return;
    const idx = r * cols + c;
    grid[idx] = grid[idx] ? 0 : 1;
    setLiveCells(countLive(grid));
    drawGrid(grid, rows, cols);
  };

  const setCell = (r, c, value) => {
    const grid = cellGridRef.current;
    if (!grid) return;
    const idx = r * cols + c;
    if (grid[idx] !== value) {
      grid[idx] = value;
      setLiveCells(countLive(grid));
      drawGrid(grid, rows, cols);
    }
  };

  const handleMouseDown = (e) => {
    const cell = getCellFromEvent(e);
    if (!cell) return;
    drawingRef.current = true;
    const idx = cell.r * cols + cell.c;
    const grid = cellGridRef.current;
    // Determine draw mode: if clicking a live cell, we kill; otherwise we birth
    drawModeRef.current = grid[idx] ? 'kill' : 'birth';
    toggleCell(cell.r, cell.c);
  };

  const handleMouseMove = (e) => {
    if (!drawingRef.current) return;
    const cell = getCellFromEvent(e);
    if (!cell) return;
    const value = drawModeRef.current === 'birth' ? 1 : 0;
    setCell(cell.r, cell.c, value);
  };

  const handleMouseUp = () => {
    drawingRef.current = false;
    drawModeRef.current = null;
  };

  // ---------- Control handlers ----------
  const handleStep = () => {
    const grid = cellGridRef.current;
    const next = stepGrid(grid, rows, cols);
    cellGridRef.current = next;
    setGeneration(g => g + 1);
    setLiveCells(countLive(next));
    drawGrid(next, rows, cols);
  };

  const handleClear = () => {
    setPlaying(false);
    initGrid(rows, cols);
  };

  const handleRandom = () => {
    const grid = makeGrid(rows, cols);
    for (let i = 0; i < grid.length; i++) {
      grid[i] = Math.random() < RANDOM_FILL_PROBABILITY ? 1 : 0;
    }
    cellGridRef.current = grid;
    setGeneration(0);
    setLiveCells(countLive(grid));
    drawGrid(grid, rows, cols);
  };

  // Preset patterns
  const placePattern = (pattern) => {
    const grid = makeGrid(rows, cols);
    const startR = Math.floor(rows / 2) - Math.floor(pattern.length / 2);
    const startC = Math.floor(cols / 2) - Math.floor(pattern[0].length / 2);
    for (let r = 0; r < pattern.length; r++) {
      for (let c = 0; c < pattern[r].length; c++) {
        const gr = startR + r;
        const gc = startC + c;
        if (gr >= 0 && gr < rows && gc >= 0 && gc < cols) {
          grid[gr * cols + gc] = pattern[r][c];
        }
      }
    }
    cellGridRef.current = grid;
    setGeneration(0);
    setLiveCells(countLive(grid));
    drawGrid(grid, rows, cols);
  };

  const presets = [
    {
      name: 'Glider',
      pattern: [
        [0,1,0],
        [0,0,1],
        [1,1,1]
      ]
    },
    {
      name: 'Blinker',
      pattern: [
        [1,1,1]
      ]
    },
    {
      name: 'Pulsar',
      pattern: [
        [0,0,1,1,1,0,0,0,1,1,1,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [0,0,1,1,1,0,0,0,1,1,1,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,1,1,1,0,0,0,1,1,1,0,0],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [1,0,0,0,0,1,0,1,0,0,0,0,1],
        [0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,1,1,1,0,0,0,1,1,1,0,0]
      ]
    },
    {
      name: 'Gosper Glider Gun',
      pattern: [
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
        [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
        [1,1,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [1,1,0,0,0,0,0,0,0,0,1,0,0,0,1,0,1,1,0,0,0,0,1,0,1,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,1,0,0,0,0,0,1,0,0,0,0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,1,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
        [0,0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
      ]
    },
    {
      name: 'Lightweight Spaceship',
      pattern: [
        [0,1,0,0,1],
        [1,0,0,0,0],
        [1,0,0,0,1],
        [1,1,1,1,0]
      ]
    }
  ];

  // ---------- Speed marks for slider ----------
  const speedMarks = [
    { value: 1, label: '1' },
    { value: 10, label: '10' },
    { value: 30, label: '30' },
    { value: 60, label: '60' }
  ];

  // ---------- Render ----------
  return (
    <Container maxWidth="lg">
      <Box sx={{ py: 2 }}>
        <Typography variant="h4" gutterBottom sx={{ fontWeight: 500 }}>
          Conway's Game of Life
        </Typography>
        <Typography variant="body1" color="text.secondary" sx={{ mb: 3 }}>
          An interactive cellular automaton devised by mathematician John Conway. 
          Click or drag on the grid to toggle cells. Use the controls to run the simulation, 
          adjust speed, or load preset patterns.
        </Typography>

        {/* Controls */}
        <Paper elevation={2} sx={{ p: 2, mb: 2 }}>
          <Box sx={{ display: 'flex', flexWrap: 'wrap', gap: 2, alignItems: 'center' }}>
            {/* Play / Pause / Step / Clear / Random */}
            <ButtonGroup variant="contained" size="small">
              <Button onClick={() => setPlaying(!playing)} color={playing ? 'error' : 'success'}>
                {playing ? '⏸ Pause' : '▶ Play'}
              </Button>
              <Button onClick={handleStep} disabled={playing}>
                ⏭ Step
              </Button>
              <Button onClick={handleClear} color="warning">
                ✕ Clear
              </Button>
              <Button onClick={handleRandom}>
                🎲 Random
              </Button>
            </ButtonGroup>

            {/* Preset patterns */}
            <ButtonGroup variant="outlined" size="small">
              {presets.map((p) => (
                <Tooltip key={p.name} title={`Load ${p.name} pattern`}>
                  <Button onClick={() => placePattern(p.pattern)}>
                    {p.name}
                  </Button>
                </Tooltip>
              ))}
            </ButtonGroup>
          </Box>

          {/* Speed slider */}
          <Box sx={{ mt: 2, maxWidth: 400 }}>
            <Typography variant="body2" gutterBottom>
              Speed: {speed} generations / sec
            </Typography>
            <Slider
              value={speed}
              onChange={(e, v) => setSpeed(v)}
              min={1}
              max={60}
              step={1}
              marks={speedMarks}
              valueLabelDisplay="auto"
              size="small"
            />
          </Box>

          {/* Stats */}
          <Box sx={{ mt: 1, display: 'flex', gap: 3 }}>
            <Typography variant="body2" color="text.secondary">
              Generation: <strong>{generation}</strong>
            </Typography>
            <Typography variant="body2" color="text.secondary">
              Live cells: <strong>{liveCells}</strong>
            </Typography>
            <Typography variant="body2" color="text.secondary">
              Grid: {cols} × {rows}
            </Typography>
          </Box>
        </Paper>

        {/* Canvas */}
        <Paper
          elevation={3}
          sx={{
            display: 'inline-block',
            p: 0.5,
            lineHeight: 0,
            cursor: 'crosshair',
            width: '100%',
            maxWidth: '100%',
            overflow: 'hidden'
          }}
        >
          <canvas
            ref={canvasRef}
            width={CANVAS_WIDTH}
            height={CANVAS_HEIGHT}
            style={{ width: '100%', height: 'auto', display: 'block' }}
            onMouseDown={handleMouseDown}
            onMouseMove={handleMouseMove}
            onMouseUp={handleMouseUp}
            onMouseLeave={handleMouseUp}
          />
        </Paper>

        {/* Rules description */}
        <Paper elevation={1} sx={{ p: 2, mt: 2 }}>
          <Typography variant="h6" gutterBottom>
            Rules
          </Typography>
          <Typography variant="body2" component="div" color="text.secondary">
            <ol style={{ margin: 0, paddingLeft: '1.5em' }}>
              <li>Any live cell with fewer than two live neighbors dies (underpopulation).</li>
              <li>Any live cell with two or three live neighbors lives on to the next generation.</li>
              <li>Any live cell with more than three live neighbors dies (overpopulation).</li>
              <li>Any dead cell with exactly three live neighbors becomes a live cell (reproduction).</li>
            </ol>
          </Typography>
        </Paper>
      </Box>
    </Container>
  );
};

// Export to global scope for browser-based JSX compilation
window.ConwaysGameOfLife = ConwaysGameOfLife;
