// MODIBU - Main App (Game Engine)

const { useState: useStateA, useEffect: useEffectA, useRef: useRefA, useCallback: useCallbackA } = React;

const PLAYER_COLORS = ['red', 'blue', 'green', 'yellow'];
const PLAYER_ICONS  = ['/car.png', '/cruise.png', '/motorbike.png', '/train.png'];
const PLAYER_NAMES_ID = ['Merah', 'Biru', 'Hijau', 'Kuning'];

// Generate session code
function generateCode() {
  const chars = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
  return 'MDB-' + Array.from({length:3}, () => chars[Math.floor(Math.random()*chars.length)]).join('');
}

// Shuffle helper
function shuffle(arr) {
  const a = [...arr];
  for (let i = a.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [a[i], a[j]] = [a[j], a[i]];
  }
  return a;
}

function App() {
  // ===== Role & Flow =====
  const [role, setRole] = useStateA(null); // 'siswa' | 'guru'
  const [screen, setScreen] = useStateA('landing');
  const [sessionCode, setSessionCode] = useStateA(generateCode());

  // ===== Player Setup =====
  const [playerNames, setPlayerNames] = useStateA(['', '', '', '']);
  const [players, setPlayers] = useStateA([
    { id: 1, name: 'Pemain 1', color: 'red',    score: 0, position: 0, icon: '/car.png', isInJail: false, jailTurns: 0, skipTurn: false, extraTurn: false, laps: 0, stats: { edukasi: 0, fakta: 0, tantangan: 0, refleksi: 0, kesempatan: 0, hukuman: 0 } },
    { id: 2, name: 'Pemain 2', color: 'blue',   score: 0, position: 0, icon: '/cruise.png', isInJail: false, jailTurns: 0, skipTurn: false, extraTurn: false, laps: 0, stats: { edukasi: 0, fakta: 0, tantangan: 0, refleksi: 0, kesempatan: 0, hukuman: 0 } },
    { id: 3, name: 'Pemain 3', color: 'green',  score: 0, position: 0, icon: '/motorbike.png', isInJail: false, jailTurns: 0, skipTurn: false, extraTurn: false, laps: 0, stats: { edukasi: 0, fakta: 0, tantangan: 0, refleksi: 0, kesempatan: 0, hukuman: 0 } },
    { id: 4, name: 'Pemain 4', color: 'yellow', score: 0, position: 0, icon: '/train.png', isInJail: false, jailTurns: 0, skipTurn: false, extraTurn: false, laps: 0, stats: { edukasi: 0, fakta: 0, tantangan: 0, refleksi: 0, kesempatan: 0, hukuman: 0 } },
  ]);

  // ===== Game State =====
  const [currentTurnIdx, setCurrentTurnIdx] = useStateA(0);
  const [diceValues, setDiceValues] = useStateA([1, 1]);
  const [isRolling, setIsRolling] = useStateA(false);
  const [isAnimating, setIsAnimating] = useStateA(false);
  const [activeModal, setActiveModal] = useStateA(null);
  const [currentQuestion, setCurrentQuestion] = useStateA(null);
  const [currentCard, setCurrentCard] = useStateA(null);
  const [gameStatus, setGameStatus] = useStateA('waiting'); // waiting | playing | paused | finished
  const [round, setRound] = useStateA(1);
  const [gradingQueue, setGradingQueue] = useStateA([]);
  const [waitingForGrade, setWaitingForGrade] = useStateA(false);
  const [maxRounds, setMaxRounds] = useStateA(2); 
  const [currentRoom, setCurrentRoom] = useStateA(null);
  const [gameLog, setGameLog] = useStateA([]);
  const [isLoaded, setIsLoaded] = useStateA(false);

  // Ref to prevent sync loops
  const lastSyncRef = useRefA(null);

  // ===== Real-time Sync (Listen) =====
  useEffectA(() => {
    if (!currentRoom || !window.EchoInstance) return;

    const channelName = 'room.' + currentRoom.code;
    console.log('App: Listening for updates on', channelName);

    window.EchoInstance.on(channelName, 'room.updated', (data) => {
      console.log('App: room.updated event received', data);
      // Avoid syncing if the data is exactly what we just sent
      const dataStr = JSON.stringify({ p: data.players, s: data.game_state, st: data.status });
      if (dataStr === lastSyncRef.current) return;

      console.log('App: Received remote update', data);
      lastSyncRef.current = dataStr;
      
      if (data.players) {
        if (role === 'siswa') {
          // Students: only merge scores from server, keep local positions/state
          setPlayers(prev => prev.map((localP, i) => {
            const serverP = data.players[i];
            if (!serverP) return localP;
            if (serverP.score !== localP.score) {
              console.log(`App: WS synced score for ${localP.name}: ${localP.score} → ${serverP.score}`);
              return { ...localP, score: serverP.score };
            }
            return localP;
          }));
        } else {
          // Guru: accept full player data (positions come from students)
          setPlayers(data.players);
        }
      }
      if (data.game_state) {
        // Only sync grading_queue (teacher clears items after grading)
        if (data.game_state.grading_queue !== undefined) setGradingQueue(data.game_state.grading_queue);
        if (data.game_state.game_log !== undefined) setGameLog(data.game_state.game_log);
        
        // SYNC MODALS (Triggered by Guru)
        if (data.game_state.active_modal !== undefined) setActiveModal(data.game_state.active_modal);
        if (data.game_state.current_question !== undefined) setCurrentQuestion(data.game_state.current_question);
        if (data.game_state.current_card !== undefined) setCurrentCard(data.game_state.current_card);

        // For guru: also sync positions, turns, dice from students
        if (role === 'guru') {
          if (data.game_state.current_turn_idx !== undefined) setCurrentTurnIdx(data.game_state.current_turn_idx);
          if (data.game_state.round !== undefined) setRound(data.game_state.round);
          if (data.game_state.dice !== undefined) setDiceValues(data.game_state.dice);
        }
        
        // Sync question pools for both
        if (data.game_state.edukasi_idx) setEdukasiPool(data.game_state.edukasi_idx);
        if (data.game_state.fakta_idx) setFaktaPool(data.game_state.fakta_idx);
        if (data.game_state.tantangan_idx) setTantanganPool(data.game_state.tantangan_idx);
        if (data.game_state.refleksi_idx) setRefleksiPool(data.game_state.refleksi_idx);
        if (data.game_state.kesempatan_idx) setKesempatanPool(data.game_state.kesempatan_idx);
        if (data.game_state.hukuman_idx) setHukumanPool(data.game_state.hukuman_idx);
      }
      if (data.status) {
        setGameStatus(data.status);
        if (data.status === 'finished') {
          setScreen('hasil');
          setActiveModal(null);
        }
      }
    });

    // Dedicated finish listener — uses minimal payload, never blocked by size or dedup logic
    window.EchoInstance.on(channelName, 'room.finished', (data) => {
      console.log('App: room.finished received! Event Data:', data);
      setGameStatus('finished');
      setScreen('hasil');
      setActiveModal(null);
    });

    return () => { if (window.EchoInstance) window.EchoInstance.leave(channelName); };
  }, [currentRoom?.code ? currentRoom.code.toUpperCase() : null]);

  // ===== Polling Fallback (Score-only sync for students) =====
  useEffectA(() => {
    if (!currentRoom || gameStatus === 'finished') return;
    
    const interval = setInterval(async () => {
      try {
        const res = await window.RoomAPI.getRoom(currentRoom.code.toUpperCase());
        if (!res.success) return;
        
        if (res.room.status === 'finished') {
          console.log('App: Polling detected game finished.');
          setGameStatus('finished');
          setScreen('hasil');
          setActiveModal(null);
          return;
        }
        
        // For students: only merge SCORES and grading_queue from server
        // Never overwrite positions, turns, or other local game state
        if (role === 'siswa' && res.room.players) {
          const serverPlayers = res.room.players;
          setPlayers(prev => prev.map((localP, i) => {
            const serverP = serverPlayers[i];
            if (!serverP) return localP;
            // Only take the score from server if it's higher (Guru gave points)
            const serverScore = serverP.score || 0;
            if (serverScore !== localP.score) {
              console.log(`App: Polling synced score for ${localP.name}: ${localP.score} → ${serverScore}`);
              return { ...localP, score: serverScore };
            }
            return localP;
          }));
          // Sync grading queue from server (guru removes items after grading)
          if (res.room.game_state?.grading_queue !== undefined) {
            setGradingQueue(res.room.game_state.grading_queue);
          }
          // Sync active modal (guru triggers material)
          if (res.room.game_state?.active_modal !== undefined) {
            setActiveModal(res.room.game_state.active_modal);
          }
        }
      } catch (err) {
        console.warn('App: Polling fallback failed', err);
      }
    }, 5000); // Check every 5 seconds
    
    return () => clearInterval(interval);
  }, [currentRoom?.code, gameStatus, role]);

  // ===== Push State to Server (Both Guru and Siswa) =====
  useEffectA(() => {
    if (!currentRoom || !window.RoomAPI) return;
    if (gameStatus !== 'playing' && gameStatus !== 'finished') return;

    const stateToSync = {
      status: gameStatus,
      players: players,
      game_state: {
        current_turn_idx: currentTurnIdx,
        round: round,
        dice: diceValues,
        grading_queue: gradingQueue,
        game_log: gameLog,
        active_modal: activeModal,
        current_question: currentQuestion,
        current_card: currentCard,
        edukasi_idx: edukasiPool,
        fakta_idx: faktaPool,
        tantangan_idx: tantanganPool,
        refleksi_idx: refleksiPool,
        kesempatan_idx: kesempatanPool,
        hukuman_idx: hukumanPool
      }
    };
    
    const stateStr = JSON.stringify({ p: stateToSync.players, s: stateToSync.game_state, st: gameStatus });
    if (stateStr === lastSyncRef.current) return;

    // Debounce sync to avoid spamming API
    const timer = setTimeout(() => {
      console.log(`App: ${role} pushing state update...`);
      lastSyncRef.current = stateStr;
      window.RoomAPI.updateState(currentRoom.code, stateToSync).catch(e => console.error('Push error:', e));
    }, 500);

    return () => clearTimeout(timer);
  }, [players, currentTurnIdx, round, diceValues, gradingQueue, gameLog, gameStatus, currentRoom?.code, role, activeModal, currentQuestion, currentCard,
      edukasiPool, faktaPool, tantanganPool, refleksiPool, kesempatanPool, hukumanPool]);

  // ===== Manual Broadcast (Bypass Debounce for Critical Actions) =====
  const broadcastUpdate = useCallbackA((customPlayers, customQueue) => {
    if (!currentRoom || !window.RoomAPI) return;
    const stateToSync = {
      status: gameStatus,
      players: customPlayers || players,
      game_state: {
        current_turn_idx: currentTurnIdx,
        round: round,
        dice: diceValues,
        grading_queue: customQueue || gradingQueue,
        game_log: gameLog,
        active_modal: customModal || activeModal,
        current_question: currentQuestion,
        current_card: currentCard,
        edukasi_idx: edukasiPool,
        fakta_idx: faktaPool,
        tantangan_idx: tantanganPool,
        refleksi_idx: refleksiPool,
        kesempatan_idx: kesempatanPool,
        hukuman_idx: hukumanPool
      }
    };
    const stateStr = JSON.stringify({ p: stateToSync.players, s: stateToSync.game_state, st: gameStatus });
    lastSyncRef.current = stateStr;
    console.log('App: Immediate broadcast push...');
    window.RoomAPI.updateState(currentRoom.code, stateToSync).catch(e => console.error('Broadcast error:', e));
  }, [players, currentTurnIdx, round, diceValues, gradingQueue, gameLog, gameStatus, currentRoom, activeModal, currentQuestion, currentCard,
      edukasiPool, faktaPool, tantanganPool, refleksiPool, kesempatanPool, hukumanPool]);

  // ===== Question Pools (indices only to save bandwidth) =====
  const [edukasiPool, setEdukasiPool] = useStateA(() => shuffle((window.ALL_EDUKASI || []).map((_, i) => i)));
  const [faktaPool, setFaktaPool] = useStateA(() => shuffle((window.ALL_FAKTA || []).map((_, i) => i)));
  const [tantanganPool, setTantanganPool] = useStateA(() => shuffle((window.ALL_TANTANGAN || []).map((_, i) => i)));
  const [refleksiPool, setRefleksiPool] = useStateA(() => shuffle((window.ALL_REFLEKSI || []).map((_, i) => i)));
  const [kesempatanPool, setKesempatanPool] = useStateA(() => shuffle((window.ALL_KARTU_KESEMPATAN || []).map((_, i) => i)));
  const [hukumanPool, setHukumanPool] = useStateA(() => shuffle((window.ALL_KARTU_HUKUMAN || []).map((_, i) => i)));

  // ===== Grading Queue (for guru) =====
  const addLog = (msg) => setGameLog(prev => [{ time: new Date().toLocaleTimeString('id-ID', {hour:'2-digit',minute:'2-digit'}), msg }, ...prev].slice(0, 50));

  // ===== Persistence =====

  useEffectA(() => {
    const saved = localStorage.getItem('modibu_state');
    if (saved) {
      try {
        const parsed = JSON.parse(saved);
        if (parsed.role) setRole(parsed.role);
        if (parsed.screen) setScreen(parsed.screen);
        if (parsed.sessionCode) setSessionCode(parsed.sessionCode);
        if (parsed.players) setPlayers(parsed.players);
        if (parsed.currentTurnIdx !== undefined) setCurrentTurnIdx(parsed.currentTurnIdx);
        if (parsed.gameStatus) setGameStatus(parsed.gameStatus);
        if (parsed.round) setRound(parsed.round);
        if (parsed.gradingQueue) setGradingQueue(parsed.gradingQueue);
        if (parsed.gameLog) setGameLog(parsed.gameLog);
        
        if (parsed.currentRoom?.code && window.RoomAPI) {
          // Validate with server
          window.RoomAPI.getRoom(parsed.currentRoom.code).then(res => {
            if (res.success && res.room.status !== 'finished') {
              setCurrentRoom(res.room);
            } else {
              handleResetSilent();
            }
            setIsLoaded(true);
          }).catch(() => {
            handleResetSilent();
            setIsLoaded(true);
          });
          return; // Wait for server before setting isLoaded
        }
      } catch (e) {
        console.error("Failed to load state", e);
        handleResetSilent();
      }
    }
    setIsLoaded(true);
  }, []);

  useEffectA(() => {
    if (!isLoaded) return;
    const state = {
      role, screen, sessionCode, players, currentTurnIdx,
      gameStatus, round, gradingQueue, gameLog, currentRoom
    };
    localStorage.setItem('modibu_state', JSON.stringify(state));
  }, [role, screen, sessionCode, players, currentTurnIdx, gameStatus, round, gradingQueue, gameLog, currentRoom, isLoaded]);

  const handleResetSilent = () => {
    localStorage.removeItem('modibu_state');
    setScreen('landing');
    setRole(null);
    setCurrentRoom(null);
  };

  const handleReset = () => {
    if (confirm('Mereset aplikasi akan menghapus semua data tersimpan. Lanjut?')) {
      localStorage.removeItem('modibu_state');
      window.location.reload();
    }
  };

  const [renderError, setRenderError] = useStateA(null);

  // ===== Pool Picker (cycles through indices) =====
  const pickFromPool = (indices, setIndices, allItems) => {
    if (indices.length === 0) {
      const reshuffled = shuffle((allItems || []).map((_, i) => i));
      setIndices(reshuffled.slice(1));
      return allItems[reshuffled[0]];
    }
    const idx = indices[0];
    setIndices(indices.slice(1));
    return allItems[idx];
  };

  // ===== Landing → Role =====
  const handlePickRole = (r) => {
    setRole(r);
    if (r === 'guru') {
      setScreen('teacher-lobby');
    } else {
      setScreen('room-code-entry');
    }
  };

  // ===== Room → Start Game (triggered by API room data) =====
  const handleStartGame = (roomData) => {
    console.log('App: Starting game with data:', roomData);
    if (!roomData) return;

    // roomData can be either a room API object or a names array (legacy)
    let newPlayers;
    if (Array.isArray(roomData)) {
      // Legacy: called with names array
      newPlayers = roomData.map((name, i) => ({
        id: i + 1, name: name || `Pemain ${i+1}`,
        color: PLAYER_COLORS[i], score: 0, position: 0, icon: PLAYER_ICONS[i],
        isInJail: false, jailTurns: 0, skipTurn: false, extraTurn: false, laps: 0,
        stats: { edukasi: 0, fakta: 0, tantangan: 0, refleksi: 0, kesempatan: 0, hukuman: 0 },
      }));
    } else {
      // From room API: roomData is the room object
      const serverPlayers = roomData.players || [];
      newPlayers = serverPlayers.map((p, i) => ({
        id: i + 1, name: p.name || `Pemain ${i+1}`,
        color: p.color || PLAYER_COLORS[i], score: p.score || 0, position: p.position || 0,
        icon: p.icon || PLAYER_ICONS[i],
        isInJail: !!p.isInJail, jailTurns: p.jailTurns || 0, skipTurn: !!p.skipTurn, extraTurn: !!p.extraTurn, laps: p.laps || 0,
        stats: p.stats || { edukasi: 0, fakta: 0, tantangan: 0, refleksi: 0, kesempatan: 0, hukuman: 0 },
      }));
      if (roomData.code) {
        setCurrentRoom(roomData);
        setSessionCode(roomData.code);
      }
    }
    
    setPlayers(newPlayers);
    setCurrentTurnIdx(0);
    setGameStatus('playing');
    setRound(1);
    setGameLog([]);
    setGradingQueue([]);
    addLog(`Permainan dimulai! Giliran ${newPlayers[0]?.name}.`);

    if (role === 'guru') {
      setScreen('guru');
    } else {
      setScreen('board');
    }
  };

  // ===== Dice Roll & Animated Movement =====
  const handleRoll = () => {
    if (isRolling || isAnimating || gameStatus !== 'playing') return;
    const player = players[currentTurnIdx];

    // Check jail
    if (player.isInJail) {
      setPlayers(prev => prev.map((p, i) => i === currentTurnIdx ? { ...p, isInJail: false, jailTurns: 0 } : p));
      addLog(`${player.name} keluar dari penjara.`);
      doAdvanceTurn();
      return;
    }
    // Check skip
    if (player.skipTurn) {
      setPlayers(prev => prev.map((p, i) => i === currentTurnIdx ? { ...p, skipTurn: false } : p));
      addLog(`${player.name} kehilangan giliran.`);
      doAdvanceTurn();
      return;
    }

    setIsRolling(true);
    const d1 = Math.floor(Math.random() * 6) + 1;
    const d2 = Math.floor(Math.random() * 6) + 1;
    const total = d1 + d2;
    const isDouble = d1 === d2;

    setTimeout(() => {
      setDiceValues([d1, d2]);
      setIsRolling(false);
      addLog(`${player.name} melempar dadu: ${d1}+${d2}=${total}${isDouble ? ' (DOUBLE!)' : ''}`);
      
      // Start sequential movement
      movePlayerSteps(currentTurnIdx, total, isDouble, player.position);
    }, 900);
  };

  const movePlayerSteps = (playerIndex, stepsLeft, isDouble, currentPos) => {
    if (stepsLeft <= 0) {
      setIsAnimating(false);
      setTimeout(() => {
        handleTileLanding(currentPos, isDouble);
      }, 400);
      return;
    }

    setIsAnimating(true);
    const nextPos = (currentPos + 1) % window.BOARD_TILES.length;
    const passedStart = (currentPos === window.BOARD_TILES.length - 1 && nextPos === 0);

    setPlayers(prev => {
      const newPlayers = [...prev];
      const p = newPlayers[playerIndex];
      
      newPlayers[playerIndex] = {
        ...p,
        position: nextPos,
        laps: p.laps + (passedStart ? 1 : 0),
        score: p.score + (passedStart ? 5 : 0),
        extraTurn: isDouble && stepsLeft === 1 ? true : p.extraTurn
      };
      return newPlayers;
    });

    if (currentPos === window.BOARD_TILES.length - 1) {
       addLog(`${players[playerIndex].name} melewati START! +5 bonus poin.`);
    }

    setTimeout(() => {
      movePlayerSteps(playerIndex, stepsLeft - 1, isDouble, nextPos);
    }, 450); // Movement speed
  };

  // ===== Tile Landing Logic =====
  const handleTileLanding = (pos, isDouble) => {
    const tile = BOARD_TILES[pos];
    const player = players[currentTurnIdx];
    const t = tile.type;

    if (t === 'edukasi') {
      const q = pickFromPool(edukasiPool, setEdukasiPool, ALL_EDUKASI);
      setCurrentQuestion({ ...q, icon: tile.icon });
      setActiveModal('edukasi');
    } else if (t === 'fakta') {
      const q = pickFromPool(faktaPool, setFaktaPool, ALL_FAKTA);
      setCurrentQuestion({ ...q, icon: tile.icon });
      setActiveModal('fakta');
    } else if (t === 'tantangan') {
      const q = pickFromPool(tantanganPool, setTantanganPool, ALL_TANTANGAN);
      setCurrentQuestion({ ...q, icon: tile.icon });
      setActiveModal('tantangan');
    } else if (t === 'refleksi') {
      const q = pickFromPool(refleksiPool, setRefleksiPool, ALL_REFLEKSI);
      setCurrentQuestion({ ...q, icon: tile.icon });
      setActiveModal('refleksi');
    } else if (t === 'kesempatan') {
      const card = pickFromPool(kesempatanPool, setKesempatanPool, ALL_KARTU_KESEMPATAN);
      setCurrentCard({ ...card, icon: tile.icon });
      setActiveModal('kartu-pos');
    } else if (t === 'hukuman') {
      const card = pickFromPool(hukumanPool, setHukumanPool, ALL_KARTU_HUKUMAN);
      setCurrentCard({ ...card, icon: tile.icon });
      setActiveModal('kartu-neg');
    } else if (t === 'penjara') {
      setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
        ? { ...p, isInJail: true, jailTurns: 1 } : p));
      addLog(`${player.name} masuk penjara! Kehilangan 1 giliran.`);
      setTimeout(() => doAdvanceTurn(), 1200);
    } else if (t === 'bonus') {
      const amount = parseInt(tile.price?.replace('+', '') || '15');
      setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
        ? { ...p, score: p.score + amount } : p));
      addLog(`${player.name} mendapat BONUS +${amount} poin!`);
      setTimeout(() => doAdvanceTurn(), 1200);
    } else if (t === 'finish') {
      addLog(`${player.name} melewati FINISH!`);
      checkGameEnd();
      if (gameStatus === 'playing') setTimeout(() => doAdvanceTurn(), 800);
    } else {
      // start or regular
      setTimeout(() => doAdvanceTurn(), 600);
    }
  };

  // ===== Answer Handlers =====
  const handleQuizAnswer = (points) => {
    const player = players[currentTurnIdx];
    const category = currentQuestion?.type === 'fakta_hoax' ? 'fakta' : 'edukasi';
    setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
      ? { ...p, score: p.score + points, stats: { ...p.stats, [category]: p.stats[category] + (points > 0 ? 1 : 0) } }
      : p));
    addLog(`${player.name} menjawab soal ${category}: ${points > 0 ? `Benar! +${points}` : 'Salah (0)'} poin.`);
    setActiveModal(null);
    setCurrentQuestion(null);
    // Show material popup after answering
    setTimeout(() => {
      setActiveModal('materi');
    }, 300);
  };

  const handleMaterialClose = () => {
    setActiveModal(null);
    doAdvanceTurn();
  };

  const handleChallengeSubmit = (text) => {
    const player = players[currentTurnIdx];
    const qType = currentQuestion?.type || 'tantangan';

    const submission = {
      id: Date.now(),
      playerIdx: currentTurnIdx,
      player: { ...player },
      type: qType,
      question: currentQuestion?.question || '',
      answer: text,
      timestamp: new Date(),
    };
    setGradingQueue(prev => [...prev, submission]);
    addLog(`${player.name} mengirim jawaban ${qType} (menunggu nilai dari Guru BK).`);

    setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
      ? { ...p, stats: { ...p.stats, [qType]: p.stats[qType] + 1 } }
      : p));

    setActiveModal(null);
    setCurrentQuestion(null);
    setWaitingForGrade(false);
    doAdvanceTurn();
  };

  const handleCardAccept = () => {
    if (!currentCard) return;
    const player = players[currentTurnIdx];
    const { effectType, effectValue } = currentCard;

    if (effectType === 'score') {
      setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
        ? { ...p, score: Math.max(0, p.score + effectValue) } : p));
      addLog(`${player.name}: ${currentCard.effect}`);
    } else if (effectType === 'move') {
      setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
        ? { ...p, position: Math.max(0, (p.position + effectValue + BOARD_TILES.length) % BOARD_TILES.length) } : p));
      addLog(`${player.name}: ${currentCard.effect}`);
    } else if (effectType === 'skip_turn') {
      setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
        ? { ...p, skipTurn: true } : p));
      addLog(`${player.name}: Kehilangan 1 giliran!`);
    } else if (effectType === 'extra_turn') {
      setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
        ? { ...p, extraTurn: true } : p));
      addLog(`${player.name}: Dapat giliran ekstra!`);
    }

    const category = currentCard.type === 'hukuman' ? 'hukuman' : 'kesempatan';
    setPlayers(prev => prev.map((p, i) => i === currentTurnIdx
      ? { ...p, stats: { ...p.stats, [category]: p.stats[category] + 1 } }
      : p));

    setActiveModal(null);
    setCurrentCard(null);
    doAdvanceTurn();
  };

  // ===== Grading (Guru) =====
  const handleGrade = (submissionId, points) => {
    const sub = gradingQueue.find(s => s.id === submissionId);
    if (!sub) return;
    
    const newPlayers = players.map((p, i) => i === sub.playerIdx
      ? { ...p, score: p.score + points } : p);
    const newQueue = gradingQueue.filter(s => s.id !== submissionId);

    setPlayers(newPlayers);
    setGradingQueue(newQueue);
    addLog(`Guru memberi nilai ${points} poin untuk jawaban ${sub.player.name}.`);
    
    // Immediate sync to server
    broadcastUpdate(newPlayers, newQueue);
  };

  // ===== Advance Turn =====
  const doAdvanceTurn = () => {
    setPlayers(prev => {
      const current = prev[currentTurnIdx];
      if (current && current.extraTurn) {
        // Extra turn — stay on same player
        addLog(`${current.name} mendapat giliran ekstra! (Double)`);
        return prev.map((p, i) => i === currentTurnIdx ? { ...p, extraTurn: false } : p);
      }
      return prev;
    });

    // Need to check extraTurn from current state
    setTimeout(() => {
      setPlayers(prev => {
        const current = prev[currentTurnIdx];
        if (current && !current.extraTurn) {
          const nextIdx = (currentTurnIdx + 1) % 4;
          setCurrentTurnIdx(nextIdx);
          addLog(`Giliran ${prev[nextIdx].name}.`);
        }
        return prev;
      });
    }, 100);
  };

  // ===== Check Game End =====
  const checkGameEnd = () => {
    const allLaps = players.every(p => p.laps >= maxRounds);
    if (allLaps) {
      setGameStatus('finished');
      setScreen('hasil');
      addLog('Permainan selesai!');
      if (currentRoom) window.RoomAPI.finishGame(currentRoom.code);
    }
  };

  // ===== End Game Manually =====
  const handleEndGame = async () => {
    if (confirm('Apakah Anda yakin ingin mengakhiri sesi ini?')) {
      try {
        setGameStatus('finished');
        setScreen('hasil');
        addLog('Permainan diakhiri oleh Guru BK.');
        if (currentRoom) {
          const res = await window.RoomAPI.finishGame(currentRoom.code.toUpperCase());
          if (!res.success) throw new Error(res.message);
        }
      } catch (err) {
        alert('Gagal mengakhiri sesi di server: ' + err.message);
      }
    }
  };

  // ===== Manual Points (Guru) =====
  const handleManualPoints = (playerIdx, amount) => {
    const newPlayers = players.map((p, i) => i === playerIdx
      ? { ...p, score: Math.max(0, p.score + amount) } : p);
    
    setPlayers(newPlayers);
    addLog(`Guru mengubah poin ${players[playerIdx].name}: ${amount > 0 ? '+' : ''}${amount}`);
    
    // Immediately broadcast to server so students see the change
    broadcastUpdate(newPlayers);
  };

  // ===== Render =====
  if (renderError) {
    return (
      <div style={{ minHeight: '100vh', background: '#F8F9FA', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20 }}>
        <div className="card" style={{ maxWidth: 400, textAlign: 'center', padding: 30 }}>
          <div style={{ fontSize: 48, marginBottom: 15 }}>⚠️</div>
          <h2 className="h-title">Waduh, Ada Masalah!</h2>
          <p style={{ color: 'var(--ink-soft)', fontSize: 14, marginBottom: 20 }}>Terjadi kesalahan saat memuat tampilan. Silakan reset aplikasi untuk mencoba lagi.</p>
          <div style={{ background: '#FFF5F5', color: '#C92A2A', padding: 10, borderRadius: 8, fontSize: 11, textAlign: 'left', marginBottom: 20, fontFamily: 'monospace', overflowX: 'auto' }}>{renderError}</div>
          <button className="btn btn-primary" onClick={handleReset}>Reset Aplikasi & Muat Ulang</button>
        </div>
      </div>
    );
  }

  if (!isLoaded) {
    return (
      <div style={{ minHeight: '100vh', background: 'linear-gradient(135deg, #E3F5FD 0%, #BDE8F9 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#1971C2', fontFamily: 'Fredoka', fontWeight: 700 }}>
        <div style={{ textAlign: 'center' }}>
          <div style={{ fontSize: 40, marginBottom: 10 }}>🎲</div>
          <div>Memuat Modibu...</div>
        </div>
      </div>
    );
  }

  return (
    <div className="app-shell">

      {screen === 'landing' && (
        <div className="stage" data-screen-label="01 Landing">
          <LandingScreen onPickRole={handlePickRole} onReset={handleReset} />
        </div>
      )}

      {screen === 'lobby' && (
        <div className="stage" data-screen-label="02 Lobby">
          <LobbyScreen
            role={role}
            sessionCode={sessionCode}
            onStart={handleStartGame}
            onBack={() => { setScreen('landing'); setRole(null); }}
          />
        </div>
      )}

      {screen === 'teacher-lobby' && (
        <div className="stage" data-screen-label="02B Teacher Lobby">
          <TeacherLobbyScreen
            onBack={() => { setScreen('landing'); setRole(null); }}
            onGameStart={handleStartGame}
          />
        </div>
      )}

      {screen === 'room-code-entry' && (
        <div className="stage" data-screen-label="02C Room Code Entry">
          <RoomCodeEntryScreen
            onBack={() => { setScreen('landing'); setRole(null); }}
            onJoin={(room) => { setCurrentRoom(room); setScreen('student-lobby'); }}
          />
        </div>
      )}

      {screen === 'student-lobby' && currentRoom && (
        <div className="stage" data-screen-label="02D Student Lobby">
          <StudentLobbyScreen
            room={currentRoom}
            onBack={() => { setScreen('room-code-entry'); }}
            onGameStart={handleStartGame}
          />
        </div>
      )}

      {(screen === 'board') && (
        <BoardScreen
          players={players}
          currentTurnIdx={currentTurnIdx}
          diceValue={diceValues[0]}
          diceValues={diceValues}
          isRolling={isRolling}
          isAnimating={isAnimating}
          onRoll={handleRoll}
          onPause={() => { setGameStatus('paused'); setScreen('landing'); }}
          onHelp={() => setActiveModal('materi-help')}
          sessionCode={sessionCode || (currentRoom ? currentRoom.code : '')}
          round={round}
          gameLog={gameLog}
          onEndGame={role === 'guru' ? handleEndGame : null}
          onOpenGuru={role === 'guru' ? () => setScreen('guru') : null}
        />
      )}

      {screen === 'guru' && (
        <div className="stage" data-screen-label="11 Panel Guru">
          <TeacherPanel
            players={players}
            currentTurnIdx={currentTurnIdx}
            sessionCode={sessionCode}
            round={round}
            gradingQueue={gradingQueue}
            gameLog={gameLog}
            onGrade={handleGrade}
            onBack={() => setScreen('board')}
            onEndGame={handleEndGame}
            onManualPoints={handleManualPoints}
            onTriggerMaterial={() => setActiveModal('materi')}
            onReset={handleReset}
          />
        </div>
      )}

      {screen === 'hasil' && (
        <div className="stage" data-screen-label="12 Hasil">
          <ResultsScreen
            role={role}
            players={players}
            sessionCode={sessionCode}
            onPlayAgain={() => { localStorage.removeItem('modibu_state'); window.location.reload(); }}
            onHome={() => { localStorage.removeItem('modibu_state'); window.location.reload(); }}
            onReset={handleReset}
          />
        </div>
      )}

      {/* MODALS */}
      {activeModal === 'edukasi' && currentQuestion && (
        <QuizModal
          data={currentQuestion}
          onClose={() => { setActiveModal(null); doAdvanceTurn(); }}
          onAnswer={handleQuizAnswer}
        />
      )}
      {activeModal === 'fakta' && currentQuestion && (
        <QuizModal
          data={currentQuestion}
          onClose={() => { setActiveModal(null); doAdvanceTurn(); }}
          onAnswer={handleQuizAnswer}
        />
      )}
      {activeModal === 'tantangan' && currentQuestion && (
        <ChallengeModal
          data={currentQuestion}
          onClose={() => { setActiveModal(null); doAdvanceTurn(); }}
          onSubmit={handleChallengeSubmit}
        />
      )}
      {activeModal === 'refleksi' && currentQuestion && (
        <ChallengeModal
          data={currentQuestion}
          onClose={() => { setActiveModal(null); doAdvanceTurn(); }}
          onSubmit={handleChallengeSubmit}
        />
      )}
      {activeModal === 'kartu-pos' && currentCard && (
        <CardModal data={currentCard} onClose={handleCardAccept} />
      )}
      {activeModal === 'kartu-neg' && currentCard && (
        <CardModal data={currentCard} onClose={handleCardAccept} />
      )}
      {activeModal === 'materi' && (
        <MaterialModal data={ALL_MATERI[Math.floor(Math.random() * ALL_MATERI.length)]} onClose={handleMaterialClose} />
      )}

      {activeModal === 'materi-help' && (
        <MaterialModal data={ALL_MATERI[Math.floor(Math.random() * ALL_MATERI.length)]} onClose={() => setActiveModal(null)} />
      )}
    </div>
  );
}

function BoardScreen({ players, currentTurnIdx, diceValue, diceValues, isRolling, onRoll, onPause, onHelp, sessionCode, round, gameLog, onEndGame, onOpenGuru }) {
  return (
    <div className="stage" data-screen-label="03 Papan Permainan" style={{
      padding: '20px 0 40px',
      display: 'flex',
      alignItems: 'center',
      justifyContent: 'center',
      minHeight: '100vh'
    }}>
      <CloudBG density="sparse" />
      <div style={{ position: 'relative', zIndex: 2, width: '100%' }}>
        <Board
          players={players}
          currentTurnIdx={currentTurnIdx}
          diceValue={diceValue}
          diceValues={diceValues}
          isRolling={isRolling}
          onRoll={onRoll}
          onPause={onPause}
          onHelp={onHelp}
          sessionCode={sessionCode}
          round={round}
          gameLog={gameLog}
          onEndGame={onEndGame}
          onOpenGuru={onOpenGuru}
        />
      </div>
    </div>
  );
}

// MOUNT - Deferred to ensure all Babel JSX files are fully parsed before mounting
(function mountApp() {
  // If student refreshes during a game (screen='board'), clear the stale state
  // so they don't get a blank screen - they'll need to rejoin the room
  try {
    const saved = localStorage.getItem('modibu_state');
    if (saved) {
      const parsed = JSON.parse(saved);
      // Only clear if we're mid-game (board/guru screen) and role is 'siswa'
      // Teachers (guru) can resume their session
      if (parsed.screen === 'board' && parsed.role === 'siswa') {
        console.log('App: Clearing stale student board state on refresh.');
        localStorage.removeItem('modibu_state');
      }
    }
  } catch(e) {
    localStorage.removeItem('modibu_state');
  }

  // Mount after a short delay to ensure all Babel-compiled JSX files are ready
  function doMount() {
    const root = document.getElementById('root');
    if (!root) return;
    try {
      ReactDOM.createRoot(root).render(React.createElement(App));
    } catch(e) {
      console.error('Mount failed:', e);
      root.innerHTML = '<div style="min-height:100vh;background:linear-gradient(135deg,#E3F5FD,#BDE8F9);display:flex;align-items:center;justify-content:center;font-family:Fredoka"><div style="text-align:center;padding:40px;background:white;border-radius:24px;box-shadow:0 8px 32px rgba(0,0,0,.1)"><div style="font-size:48px;margin-bottom:12px">⚠️</div><h2 style="color:#1971C2;margin-bottom:8px">Gagal Memuat Aplikasi</h2><p style="color:#868E96;margin-bottom:20px">Terjadi kesalahan. Silakan muat ulang halaman.</p><button onclick="localStorage.clear();location.reload()" style="background:#4DABF7;color:white;border:none;padding:12px 28px;border-radius:999px;font-family:Fredoka;font-size:16px;font-weight:700;cursor:pointer">Muat Ulang</button></div></div>';
    }
  }

  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', doMount);
  } else {
    doMount();
  }
})();
