import React, { useEffect, useRef, useState } from "react";
import { Box, Typography, useTheme, useMediaQuery } from "@mui/material";
import { motion, useAnimation } from "framer-motion";
import { useSoundSystem } from "../contexts/SoundContext";
// Animation timing configuration
const SLOT_ANIMATION_DURATION = 2; // Duration of each slot animation
const SLOT_SPEED = 1; // Base speed of the slot animation (higher = faster)
const TOTAL_ANIMATION_DURATION = 1; // Total duration for each slot reel in seconds
const SLOT_START_DELAY = 0.75; // Delay between each slot start in seconds
// Random words for each category
const RANDOM_STYLES = [
"Manga",
"Comics",
"Franco-Belge",
"Steampunk",
"Cyberpunk",
];
const RANDOM_GENRES = ["Action", "Fantasy", "Sci-Fi", "Mystery", "Horror"];
const RANDOM_EPOCHS = ["Future", "Medieval", "Modern", "Ancient", "Victorian"];
const SlotReel = ({ words, isActive, finalValue, onComplete, delay = 0 }) => {
const containerRef = useRef(null);
const controls = useAnimation();
const [reelItems, setReelItems] = useState([]);
const [isVisible, setIsVisible] = useState(false);
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const { playSound } = useSoundSystem();
const lastPositionRef = useRef(0);
const itemHeightRef = useRef(0);
useEffect(() => {
if (isActive) {
const repeatedWords = Array(20)
.fill([...words])
.flat()
.map((word) => ({ word, id: Math.random() }));
repeatedWords.push({ word: finalValue, id: "final" });
setReelItems(repeatedWords);
const itemHeight = isMobile ? 60 : 80;
itemHeightRef.current = itemHeight;
const totalHeight = repeatedWords.length * itemHeight;
setTimeout(() => {
setIsVisible(true);
controls
.start({
y: [-itemHeight, -totalHeight + itemHeight],
transition: {
duration: TOTAL_ANIMATION_DURATION / SLOT_SPEED,
ease: [0.25, 0.1, 0.25, 1.0],
times: [0, 1],
onUpdate: (latest) => {
// Calculer l'index du mot actuel basé sur la position
const currentPosition = Math.abs(latest);
const currentIndex = Math.floor(currentPosition / itemHeight);
// Si on a changé de mot, jouer le son
if (
Math.floor(lastPositionRef.current / itemHeight) !==
currentIndex
) {
// Vérifier si c'est le dernier mot (final)
const isFinalWord = currentIndex === repeatedWords.length - 1;
// Jouer le son approprié
if (isFinalWord) {
playSound("lock");
} else {
playSound("tick", "normal");
}
}
lastPositionRef.current = currentPosition;
},
},
})
.then(() => {
onComplete?.();
});
}, delay * SLOT_START_DELAY * 1000);
}
return () => {
lastPositionRef.current = 0;
};
}, [isActive, finalValue, words, delay, isMobile, playSound]);
return (
{reelItems.map(({ word, id }) => (
{word}
))}
);
};
const SlotSection = ({ label, value, delay, isActive, onComplete, words }) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
return (
{label}
);
};
export const UniverseSlotMachine = ({
style,
genre,
epoch,
activeIndex = 0,
onComplete,
}) => {
const theme = useTheme();
const isMobile = useMediaQuery(theme.breakpoints.down("sm"));
const handleSlotComplete = (index) => {
if (index === 2 && activeIndex >= 2) {
setTimeout(() => {
onComplete?.();
}, SLOT_ANIMATION_DURATION * 1000);
}
};
return (
Finding a universe
= 0}
onComplete={() => handleSlotComplete(0)}
/>
= 1}
onComplete={() => handleSlotComplete(1)}
/>
= 2}
onComplete={() => handleSlotComplete(2)}
/>
);
};