import { useState, useEffect } from 'react'; import { motion, AnimatePresence } from 'framer-motion'; import Image from 'next/image'; import { GameState, GamePhase, Player, GAME_CONFIG } from '../../../shared/types'; import MissionReveal from './MissionReveal'; import MissionResult from './MissionResult'; interface GameBoardProps { gameState: GameState; currentPlayerId: string; actions: any; } export default function GameBoard({ gameState, currentPlayerId, actions }: GameBoardProps) { const [selectedTeam, setSelectedTeam] = useState([]); // Hooks para FASE REVEAL ROLE const [revealCard, setRevealCard] = useState(false); // Orden aleatorio de cartas de misión (se genera una vez) const [cardOrder] = useState(() => Math.random() > 0.5); // Track del voto de misión del jugador const [missionVote, setMissionVote] = useState(null); // Timer para avanzar automáticamente en REVEAL_ROLE useEffect(() => { if (gameState.phase === 'reveal_role' as any) { const timer = setTimeout(() => { actions.finishReveal(); }, 10000); return () => clearTimeout(timer); } }, [gameState.phase, actions]); // Reset missionVote cuando cambia la fase useEffect(() => { if (gameState.phase !== GamePhase.MISSION) { setMissionVote(null); } }, [gameState.phase]); const currentPlayer = gameState.players.find(p => p.id === currentPlayerId); const isLeader = gameState.currentLeaderId === currentPlayerId; // FIX: Usar currentLeaderId del estado const config = GAME_CONFIG[gameState.players.length as keyof typeof GAME_CONFIG]; const currentQuestSize = config?.quests[gameState.currentRound - 1]; // Manejar selección de equipo const toggleTeamSelection = (playerId: string) => { if (selectedTeam.includes(playerId)) { setSelectedTeam(selectedTeam.filter(id => id !== playerId)); } else { if (selectedTeam.length < currentQuestSize) { setSelectedTeam([...selectedTeam, playerId]); } } }; const handleMissionVote = (vote: boolean) => { setMissionVote(vote); actions.voteMission(vote); }; // Componente de Debug para mostrar facción const DebugInfo = () => (
🐛 DEBUG INFO
Fase: {gameState.phase}
ID: {currentPlayerId}
Facción: {currentPlayer?.faction || 'UNDEFINED'}
Rol: {currentPlayer?.role || 'UNDEFINED'}
{gameState.currentLeaderId && (
Líder: {gameState.currentLeaderId === currentPlayerId ? 'TÚ' : gameState.currentLeaderId}
)}
); // Coordenadas porcentuales de los hexágonos de misión en el mapa const missionCoords = [ { left: '12%', top: '55%' }, // Misión 1 { left: '28%', top: '15%' }, // Misión 2 { left: '52%', top: '25%' }, // Misión 3 { left: '42%', top: '70%' }, // Misión 4 { left: '82%', top: '40%' }, // Misión 5 ]; // --- UI/Efectos para FASES TEMPRANAS --- const isHost = gameState.hostId === currentPlayerId; // FASE INTRO if (gameState.phase === 'intro' as any) { return (
Battlefield

Guerra Total

{/* Audio Auto-Play */}
); } // FASE REVEAL ROLE NO HOOKS HERE if (gameState.phase === 'reveal_role' as any) { // Determinar imagen basada en el rol // Mapeo básico: // Merlin -> good_merlin.png // Percival -> good_percival.png // Servant -> good_soldier_X.png (random) // Assassin -> evil_assassin.png // Morgana -> evil_morgana.png // Mordred -> evil_mordred.png // Oberon -> evil_oberon.png // Minion -> evil_minion_X.png let roleImage = '/assets/images/characters/good_soldier_1.png'; // Default const role = currentPlayer?.role; if (role === 'merlin') roleImage = '/assets/images/characters/good_merlin.png'; else if (role === 'assassin') roleImage = '/assets/images/characters/evil_assassin.png'; else if (role === 'percival') roleImage = '/assets/images/characters/good_percival.png'; else if (role === 'morgana') roleImage = '/assets/images/characters/evil_morgana.png'; else if (role === 'mordred') roleImage = '/assets/images/characters/evil_mordred.png'; else if (role === 'oberon') roleImage = '/assets/images/characters/evil_oberon.png'; else if (role === 'loyal_servant') { // Random soldier 1-5 const idx = (currentPlayerId.charCodeAt(0) % 5) + 1; roleImage = `/assets/images/characters/good_soldier_${idx}.png`; } else if (role === 'minion') { // Random minion 1-3 const idx = (currentPlayerId.charCodeAt(0) % 3) + 1; roleImage = `/assets/images/characters/evil_minion_${idx}.png`; } return (
{/* FONDO (Mismo que Roll Call) */}
Resistance HQ

Tu Identidad Secreta

Desliza hacia arriba para revelar

{/* Carta Revelada (Fondo) */}
Role
{role?.replace('_', ' ')}
{/* Reverso de Carta (Draggable) */} { // Reducir umbral a -50 para facilitar if (info.offset.y < -50) { setRevealCard(true); } }} whileHover={{ scale: 1.02 }} whileTap={{ scale: 0.98, cursor: 'grabbing' }} animate={revealCard ? { y: -1000, opacity: 0 } : { y: 0, opacity: 1 }} className="absolute inset-0 w-full h-full rounded-xl overflow-hidden shadow-2xl z-20 cursor-grab active:cursor-grabbing hover:ring-2 hover:ring-white/50 transition-all" > Card Back
); } // FASE ROLL CALL if (gameState.phase === 'roll_call' as any) { return (
{/* Debug Info */}
Resistance HQ

Pasando Lista...

{isHost && (
); } return (
{/* Debug Info */}
Game Background
{/* --- MAPA TÁCTICO (TABLERO) --- */}
Tactical Map {/* TOKENS SOBRE EL MAPA */} {missionCoords.map((coord, idx) => { const result = gameState.questResults[idx]; const isCurrent = gameState.currentRound === idx + 1; return (
{/* Marcador de Ronda Actual */} {isCurrent && ( Current Round )} {/* Resultado de Misión (Éxito/Fracaso) */} {result === true && ( Success )} {result === false && ( Fail )}
); })} {/* TRACK DE VOTOS FALLIDOS (Pequeño indicador en la esquina inferior izquierda del mapa) */}
Votos Rechazados
{[...Array(5)].map((_, i) => (
))}
{/* --- ÁREA DE JUEGO (CARTAS Y ACCIONES) --- */}
{/* FASE: VOTACIÓN DE LÍDER */} {gameState.phase === 'vote_leader' as any && (

Confirmar Líder

¿Aceptas a {gameState.players.find(p => p.id === gameState.currentLeaderId)?.name} como Líder?
{/* Timer */} {!gameState.leaderVotes?.[currentPlayerId] && ( actions.voteLeader(null)} /> )}
{gameState.leaderVotes?.[currentPlayerId] === undefined ? (
) : (
VOTO REGISTRADO. ESPERANDO AL RESTO...
)}
)} {/* FASE: CONSTRUCCIÓN DE EQUIPO */} {gameState.phase === GamePhase.TEAM_BUILDING && ( {/* Información del líder */}
Leader
Líder Actual
{gameState.players.find(p => p.id === gameState.currentLeaderId)?.name || 'Desconocido'}
Leader
{/* Mensaje para el líder o para los demás */}

{isLeader ? '🎯 TU TURNO: ELIGE TU EQUIPO' : '⏳ ESPERANDO AL LÍDER...'}

Se necesitan {currentQuestSize} agentes para la misión #{gameState.currentRound}.

{/* Contador de seleccionados */} {isLeader && (
Seleccionados: {selectedTeam.length} / {currentQuestSize}
)} {isLeader && ( )} {!isLeader && (
El líder está seleccionando el equipo de misión...
)}
)} {/* FASE: VOTACIÓN DE EQUIPO */} {gameState.phase === GamePhase.VOTING_TEAM && (

PROPUESTA DE MISIÓN

{gameState.proposedTeam.map(id => { const p = gameState.players.find(pl => pl.id === id); return (
{p?.name}
); })}
{!currentPlayer?.hasVoted ? (
) : (
VOTO REGISTRADO. ESPERANDO AL RESTO... ```
)}
)} {/* FASE: MISIÓN */} {gameState.phase === GamePhase.MISSION && ( {gameState.proposedTeam.includes(currentPlayerId) ? (

🎯 ¡ESTÁS EN LA MISIÓN!

Elige el resultado de tu participación

{/* DEBUG INFO - TEMPORAL */}
Debug: Tu ID: {currentPlayerId} | Equipo: [{gameState.proposedTeam.join(', ')}]
Tu facción: {currentPlayer?.faction || 'UNDEFINED'} | Rol: {currentPlayer?.role || 'UNDEFINED'}
{/* Cartas en orden aleatorio */}
{cardOrder ? ( <> {/* Carta de Éxito primero */} {/* Carta de Sabotaje segundo (solo para espías) */} {currentPlayer?.faction === 'spies' && ( )} ) : ( <> {/* Carta de Sabotaje primero (solo para espías) */} {currentPlayer?.faction === 'spies' && ( )} {/* Carta de Éxito segundo */} )}
) : (
La misión está en curso...
Esperando a que el equipo complete su votación.
)}
)} {/* FASE: REVELACIÓN DE CARTAS */} {gameState.phase === 'mission_reveal' as any && ( actions.finishMissionReveal()} /> )} {/* FASE: RESULTADO DE MISIÓN */} {gameState.phase === 'mission_result' as any && ( isHost && actions.finishMissionResult()} /> )}
{/* JUGADORES (TIENDA DE CAMPAÑA) */}
{gameState.players.map((player) => { const isSelected = selectedTeam.includes(player.id); const isMe = player.id === currentPlayerId; // Avatar logic const avatarSrc = `/assets/images/characters/${player.avatar}`; return (
isLeader && gameState.phase === GamePhase.TEAM_BUILDING && toggleTeamSelection(player.id)} className={` relative flex flex-col items-center cursor-pointer transition-all duration-300 ${isSelected ? 'scale-110' : 'scale-100 opacity-80 hover:opacity-100'} `} > {/* Avatar */}
{player.name} {/* Icono de Líder */} {gameState.currentLeaderId === player.id && (
L
)} {/* Icono de Miembro del Equipo de Misión */} {gameState.proposedTeam.includes(player.id) && ( gameState.phase === GamePhase.VOTING_TEAM || gameState.phase === GamePhase.MISSION || gameState.phase === 'mission_reveal' as any || gameState.phase === 'mission_result' as any ) && (
)}
{/* Nombre */} {player.name}
); })}
{/* HISTÓRICO DE MISIONES (Esquina superior derecha) */} {gameState.missionHistory.length > 0 && (
Historial
{gameState.missionHistory.map((mission, idx) => (
{mission.round}
))}
)}
); } // Subcomponente para el Timer de Votación function VotingTimer({ onTimeout }: { onTimeout: () => void }) { const [timeLeft, setTimeLeft] = useState(10); useEffect(() => { if (timeLeft <= 0) { onTimeout(); return; } const interval = setInterval(() => setTimeLeft(t => t - 1), 1000); return () => clearInterval(interval); }, [timeLeft, onTimeout]); return (
{timeLeft}
); }