const { useState, useEffect, useRef } = React;

const ALPHABET = "ABCDEFGHIJKLMNOPQRSTUVWXYZ".split("");
const ROW_LAYOUT = [6, 8, 8, 4];
const API_URL = "game_server.php";
const MOVES_PER_TURN = 4;

const BLOCK_COLORS = ALPHABET.map((_, i) => [
  "#E84B3A", "#F07A2A", "#F5C518", "#4CAF50", "#2196F3", "#9C27B0", "#00BCD4", "#FF5722", "#E91E63", "#607D8B", "#795548", "#009688", "#3F51B5", "#8BC34A", "#FF9800", "#F44336", "#673AB7", "#03A9F4", "#CDDC39", "#FFC107", "#76FF03", "#00E5FF", "#FF4081", "#AA00FF", "#FFAB40", "#69F0AE"
][i % 26]);

const FALLEN_STYLES = ALPHABET.map((_, i) => {
  const rotation = (Math.random() - 0.5) * 70;
  return {
    rotate: rotation,
    spellingRotate: rotation * 0.4,
    dx: (Math.random() - 0.5) * 25,
    dy: (Math.random() - 0.5) * 15 + 5,
    scale: 0.85 + Math.random() * 0.15,
  };
});

function darken(hex) {
  if (!hex) return "#000";
  const num = parseInt(hex.replace("#", ""), 16);
  const r = Math.max(0, ((num >> 16) & 0xff) - 50);
  const g = Math.max(0, ((num >> 8) & 0xff) - 50);
  const b = Math.max(0, (num & 0xff) - 50);
  return `#${((r << 16) | (g << 8) | b).toString(16).padStart(6, "0")}`;
}

const playSound = (fileName) => {
  try {
    const audio = new Audio(`sounds/${fileName}`);
    audio.play().catch(() => { }); // catch and ignore if browser blocks autoplay
  } catch (e) { }
};

// Cache the best available English voice once the browser loads its voice list
let _bestVoice = null;
function getBestVoice() {
  if (_bestVoice) return _bestVoice;
  const voices = window.speechSynthesis.getVoices();
  if (!voices.length) return null;
  // Priority: Google US English > Google English > Microsoft (neural) > any en-US > any en
  const priority = [
    v => v.name === 'Google US English',
    v => v.name.startsWith('Google') && v.lang.startsWith('en'),
    v => v.name.startsWith('Microsoft') && v.lang === 'en-US' && v.name.includes('Natural'),
    v => v.name.startsWith('Microsoft') && v.lang === 'en-US',
    v => v.lang === 'en-US',
    v => v.lang.startsWith('en'),
  ];
  for (const test of priority) {
    const found = voices.find(test);
    if (found) { _bestVoice = found; return found; }
  }
  return null;
}
// Warm up the voice cache as soon as voices are ready
if (window.speechSynthesis) {
  window.speechSynthesis.onvoiceschanged = () => { _bestVoice = null; getBestVoice(); };
  getBestVoice();
}

const playTTS = (text) => {
  if (!window.speechSynthesis) return;
  window.speechSynthesis.cancel();
  const utterance = new SpeechSynthesisUtterance(text);
  utterance.lang = "en-US";
  const voice = getBestVoice();
  if (voice) utterance.voice = voice;
  window.speechSynthesis.speak(utterance);
};

async function safeFetch(url) {
  try {
    const res = await fetch(url + "&_t=" + Date.now());
    const contentType = res.headers.get("content-type");
    if (!contentType || !contentType.includes("application/json")) return { status: "error" };
    return await res.json();
  } catch (err) { return { status: "error" }; }
}

function Cloud({ x, y, scale, speed }) {
  return (
    <div style={{ position: "absolute", left: `${x}%`, top: `${y}%`, opacity: 0.9, transform: `scale(${scale})`, animation: `cloudDrift ${speed}s ease-in-out infinite alternate`, pointerEvents: "none", zIndex: 0, filter: "drop-shadow(0 6px 10px rgba(0,0,0,0.08))" }}>
      <style>{`@keyframes cloudDrift{0%{transform:translateX(-12px)}100%{transform:translateX(12px)}}`}</style>
      <svg width="120" height="60" viewBox="0 0 120 60">
        {/* Fluffy white ellipses with flat bottom structure */}
        <ellipse cx="60" cy="45" rx="55" ry="15" fill="white" />
        <ellipse cx="40" cy="35" rx="28" ry="25" fill="white" />
        <ellipse cx="75" cy="32" rx="26" ry="24" fill="white" />
        <ellipse cx="20" cy="40" rx="18" ry="16" fill="white" />
        <ellipse cx="95" cy="42" rx="15" ry="14" fill="white" />
        <ellipse cx="58" cy="20" rx="22" ry="20" fill="white" />
      </svg>
    </div>
  );
}

function Toys() {
  return (
    <div style={{ position: "absolute", right: 25, top: -45, display: "flex", alignItems: "flex-end", zIndex: 2 }}>
      {/* Green Block */}
      <div style={{ width: 26, height: 26, background: "#8BC34A", borderRadius: 4, display: "flex", alignItems: "center", justifyContent: "center", boxShadow: "0 4px 0 #558B2F", border: "2px solid #558B2F", transform: "translateY(-14px)" }}></div>
      {/* Red Block A */}
      <div style={{ width: 35, height: 35, background: "#E53935", borderRadius: 4, display: "flex", alignItems: "center", justifyContent: "center", boxShadow: "0 4px 0 #B71C1C", border: "2px solid #B71C1C", color: "white", fontWeight: 900, fontSize: 20, transform: "translateX(-15px)" }}></div>
      {/* Yellow Triangle */}
      <svg width="34" height="34" viewBox="0 0 40 40" style={{ transform: "translateX(-15px) translateY(-5px)", overflow: "visible" }}>
        <polygon points="20,0 0,35 40,35" fill="#FFCA28" stroke="#FF8F00" strokeWidth="3" strokeLinejoin="round" />
        <path d="M 0 35 L 40 35" stroke="#FF8F00" strokeWidth="6" strokeLinecap="round" />
        <circle cx="20" cy="20" r="5" fill="#FF8F00" />
      </svg>
      {/* Blue Circle Block */}
      <div style={{ width: 32, height: 32, background: "#29B6F6", borderRadius: 6, display: "flex", alignItems: "center", justifyContent: "center", boxShadow: "0 4px 0 #0277BD", border: "2px solid #0277BD", transform: "translateX(-10px) translateY(-0px)" }}>
        <div style={{ width: 14, height: 14, border: "3px solid #0277BD", borderRadius: "50%" }}></div>
      </div>
    </div>
  );
}

function Star({ x, y, size, delay = 0 }) {
  return (
    <div style={{ position: "absolute", left: `${x}%`, top: `${y}%`, animation: `twinkle 2.5s ease-in-out infinite ${delay}s alternate`, zIndex: 0, opacity: 0.8 }}>
      <style>{`@keyframes twinkle{0%{transform:scale(0.7) rotate(-15deg);opacity:0.3}100%{transform:scale(1.2) rotate(15deg);opacity:1}}`}</style>
      <svg width={size} height={size} viewBox="0 0 24 24">
        <path d="M12 2L14.5 9L22 9.5L16 14.5L18 22L12 17.5L6 22L8 14.5L2 9.5L9.5 9L12 2Z" fill="#FFF176" stroke="#FBC02D" strokeWidth="1.5" strokeLinejoin="round" />
      </svg>
    </div>
  );
}

function MonkeyBubble({ visible, message }) {
  return (
    <div style={{ display: "flex", alignItems: "flex-start", gap: 10, background: "white", borderRadius: 18, padding: visible ? "8px 12px" : "0 12px", boxShadow: visible ? "0 4px 15px rgba(0,0,0,0.12)" : "none", border: visible ? "3px solid #E84B3A" : "0 solid transparent", maxWidth: 500, width: "92%", margin: visible ? "0 auto 10px" : "0 auto", opacity: visible ? 1 : 0, transform: visible ? "translateY(0) scale(1)" : "translateY(-10px) scale(0.95)", transition: "all 0.4s ease", minHeight: visible ? 50 : 0, height: visible ? "auto" : 0, overflow: "hidden", zIndex: 80, position: "relative" }}>
      <svg width="40" height="50" viewBox="0 0 60 70" fill="none" style={{ flexShrink: 0 }}>
        <ellipse cx="30" cy="52" rx="16" ry="18" fill="#8B5E3C" /><ellipse cx="30" cy="54" rx="9" ry="11" fill="#D4956B" />
        <circle cx="30" cy="26" r="18" fill="#8B5E3C" /><ellipse cx="30" cy="30" rx="12" ry="9" fill="#D4956B" />
        <circle cx="25" cy="24" r="3.5" fill="white" /><circle cx="35" cy="24" r="3.5" fill="white" />
        <path d="M24 31 Q30 36 36 31" stroke="#8B5E3C" strokeWidth="1.5" fill="none" strokeLinecap="round" />
        <circle cx="12" cy="26" r="7" fill="#8B5E3C" /><circle cx="48" cy="26" r="7" fill="#8B5E3C" />
      </svg>
      <div style={{ background: "#FFF8E1", borderRadius: 10, padding: "6px 10px", fontSize: 13, fontWeight: 700, color: "#5D4037", lineHeight: 1.3, flex: 1 }}>{message}</div>
    </div>
  );
}

function FancyTitle({ style }) {
  const letters1 = [
    { char: 'A', color: "#FF453A" }, { char: 'L', color: "#FF9F0A" }, { char: 'P', color: "#FFD60A" }, { char: 'H', color: "#4CAF50" }, { char: 'A', color: "#32ADE6" }, { char: 'B', color: "#007AFF" }, { char: 'E', color: "#AF52DE" }, { char: 'T', color: "#FF2D55" }
  ];
  const letters2 = [
    { char: 'S', color: "#FF453A" }, { char: 'O', color: "#FF9F0A" }, { char: 'R', color: "#FFD60A" }, { char: 'T', color: "#4CAF50" }, { char: 'E', color: "#32ADE6" }, { char: 'R', color: "#AF52DE" }
  ];
  const renderRow = (arr) => (
    <div style={{ display: "flex", justifyContent: "center", gap: 6, lineHeight: 1 }}>
      {arr.map((l, i) => (
        <span key={i} style={{
          color: l.color,
          fontSize: clamp(40, 10, 65),
          fontWeight: 900,
          WebkitTextStroke: "2px white",
          textShadow: `0 4px 0 ${darken(l.color)}, 0 6px 12px rgba(0,0,0,0.3)`
        }}>{l.char}</span>
      ))}
    </div>
  );
  return (
    <div style={{ display: "flex", flexDirection: "column", gap: 5, alignItems: "center", marginBottom: 20, zIndex: 10, position: "relative", ...style }}>
      {renderRow(letters1)}
      {renderRow(letters2)}
      <div style={{ color: "white", fontWeight: 800, fontSize: clamp(14, 4, 18), marginTop: 12, textShadow: "0 2px 4px rgba(0,0,0,0.3)", letterSpacing: 1 }}>A Game for Young Explorers!</div>
    </div>
  );
}

function Balloons({ style, isPlaying, isDragging }) {
  // Float higher out of the way on mobile if we're actively playing and dragging
  const shiftUp = isPlaying && isDragging;
  return (
    <svg width="100" height="150" viewBox="0 0 100 150" style={{ ...style, opacity: shiftUp ? 0.3 : 0.9, transform: `${style.transform || ''} translateY(${shiftUp ? '-40px' : '0px'})`, transition: "all 0.5s ease", animation: "float 4s ease-in-out infinite alternate", zIndex: 1, pointerEvents: "none" }}>
      <style>{`@keyframes float{0%{transform:translateY(0)}100%{transform:translateY(-15px)}}`}</style>
      <path d="M40 100 Q 30 140 20 150" stroke="#E84B3A" strokeWidth="2" fill="none" />
      <path d="M60 90 Q 55 130 50 150" stroke="#F5C518" strokeWidth="2" fill="none" />
      <path d="M80 110 Q 75 140 70 155" stroke="#29B6F6" strokeWidth="2" fill="none" />
      <circle cx="35" cy="50" r="30" fill="#E84B3A" />
      <circle cx="65" cy="40" r="28" fill="#F5C518" />
      <circle cx="85" cy="65" r="24" fill="#29B6F6" />
      <circle cx="25" cy="40" r="4" fill="black" opacity="0.6" />
      <circle cx="45" cy="40" r="4" fill="black" opacity="0.6" />
      <path d="M30 60 Q35 65 40 60" stroke="black" strokeWidth="2" fill="none" opacity="0.6" />
      <circle cx="55" cy="30" r="4" fill="black" opacity="0.6" />
      <circle cx="75" cy="30" r="4" fill="black" opacity="0.6" />
      <path d="M60 50 Q65 55 70 50" stroke="black" strokeWidth="2" fill="none" opacity="0.6" />
      <circle cx="78" cy="58" r="3.5" fill="black" opacity="0.6" />
      <circle cx="92" cy="58" r="3.5" fill="black" opacity="0.6" />
      <path d="M82 72 Q85 76 88 72" stroke="black" strokeWidth="2" fill="none" opacity="0.6" />
    </svg>
  );
}

function Lobby({ onJoin }) {
  const [name, setName] = useState("");
  const [room, setRoom] = useState("");
  const [isInvite, setIsInvite] = useState(false);
  const [vocabData, setVocabData] = useState([]);
  const [levels, setLevels] = useState([]);
  const [selectedMode, setSelectedMode] = useState(null); // null, 'alphabet', or 'spelling'

  useEffect(() => {
    const urlParams = new URL(window.location.href).searchParams;
    const r = urlParams.get('room');
    if (r) {
      setRoom(r.toUpperCase());
      setIsInvite(true);
    }

    // Fetch Eiken vocab
    Promise.all([
      fetch('vocab/EIKEN-5-vocab.json').then(r => r.json()),
      fetch('vocab/EIKEN-4-vocab.json').then(r => r.json())
    ]).then(([eiken5, eiken4]) => {
      const combinedVocab = [...(eiken5.grade_5_vocab || []), ...(eiken4.grade_4_vocab || [])];
      setVocabData(combinedVocab);

      // Group into levels of 15 words
      const numLevels = Math.ceil(combinedVocab.length / 15);
      const newLevels = Array.from({ length: numLevels }, (_, i) => ({
        id: i + 1,
        words: combinedVocab.slice(i * 15, (i + 1) * 15)
      }));
      setLevels(newLevels);
    }).catch(err => console.error("Failed to load vocab:", err));
  }, []);
  const handleJoin = async (levelId = null, forcedMode = null) => {
    if (!name.trim()) return alert("Enter name!");
    let targetRoom = room.toUpperCase();

    // Creating a new room
    if (forcedMode === 'alphabet' || levelId !== null) {
      if (forcedMode === 'alphabet') {
        const data = await safeFetch(`${API_URL}?action=create&mode=alphabet`);
        if (data.room) targetRoom = data.room;
        else return;
      } else if (levelId !== null) {
        const selectedLevel = levels.find(l => l.id === levelId);
        if (!selectedLevel) return;

        // Pick 10 random words
        const shuffled = [...selectedLevel.words].sort(() => 0.5 - Math.random());
        const selectedWords = shuffled.slice(0, 10).map(w => ({ word: w.word, japanese: w.japanese }));

        targetRoom = `LVL${levelId}`;
        const firstWord = selectedWords[0].word;
        const data = await safeFetch(`${API_URL}?action=create&custom_room=${targetRoom}&mode=spelling&word=${encodeURIComponent(firstWord)}&words=${encodeURIComponent(JSON.stringify(selectedWords))}`);
        if (data.room) targetRoom = data.room;
        else return;
      }
    } else {
      if (!targetRoom) return alert("Enter Room Code!");
    }
    onJoin(name, targetRoom);
  };
  return (
    <div style={{ padding: 10, width: "100%", height: "100dvh", display: "flex", flexDirection: "column", alignItems: "center", background: "linear-gradient(180deg,#A1DDFA 0%,#A2E9C2 100%)", overflowY: "auto", overflowX: "hidden" }}>
      <div style={{ margin: "auto", width: "100%", display: "flex", flexDirection: "column", alignItems: "center", padding: "20px 0" }}>
        <div style={{ position: "relative", marginBottom: 20 }}>
          <Balloons style={{ position: "absolute", left: -30, top: 40 }} />
          <FancyTitle />
        </div>
        <div style={{ background: "white", padding: 30, borderRadius: 24, boxShadow: "0 10px 40px rgba(0,0,0,0.15)", maxWidth: 380, width: "100%", zIndex: 10, position: "relative" }}>
          <input placeholder="Name" value={name} onChange={e => setName(e.target.value)} style={{ width: "100%", padding: 14, borderRadius: 12, border: "2px solid #ddd", marginBottom: 10, fontSize: 16, textAlign: "center" }} />
          {!isInvite ? (
            <>
              <input placeholder="Room" value={room} onChange={e => setRoom(e.target.value.toUpperCase())} style={{ width: "100%", padding: 14, borderRadius: 12, border: "2px solid #ddd", marginBottom: 20, fontSize: 16, textAlign: "center" }} />
              <div style={{ display: "flex", gap: 10, marginBottom: 20 }}>
                <button onClick={() => handleJoin(null)} style={{ flex: 1, padding: 14, borderRadius: 12, background: "#2196F3", color: "white", border: "none", fontWeight: 800, cursor: "pointer", boxShadow: "0 4px 0 #1976D2" }}>Join Room</button>
              </div>

              <div style={{ height: 2, background: "rgba(0,0,0,0.1)", margin: "0 20px 20px" }}></div>
              <h3 style={{ color: "#333", textAlign: "center", margin: "0 0 15px 0" }}>Create New Game</h3>

              {!selectedMode && (
                <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                  <button onClick={() => handleJoin(null, 'alphabet')} style={{ padding: 14, borderRadius: 12, background: "#FF9800", color: "white", border: "none", fontWeight: 800, cursor: "pointer", boxShadow: "0 4px 0 #F57C00", fontSize: 16 }}>Alphabet Sorter</button>
                  <button onClick={() => setSelectedMode('spelling')} style={{ padding: 14, borderRadius: 12, background: "#4CAF50", color: "white", border: "none", fontWeight: 800, cursor: "pointer", boxShadow: "0 4px 0 #388E3C", fontSize: 16 }}>Spelling Game</button>
                </div>
              )}

              {selectedMode === 'spelling' && levels.length > 0 && (
                <div style={{ marginTop: 10 }}>
                  <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", marginBottom: 10 }}>
                    <h4 style={{ color: "#333", margin: 0 }}>Select Level</h4>
                    <button onClick={() => setSelectedMode(null)} style={{ background: "none", border: "none", color: "#666", cursor: "pointer", fontSize: 14, fontWeight: "bold", textDecoration: "underline" }}>Back</button>
                  </div>
                  <div style={{ display: "grid", gridTemplateColumns: "repeat(5, 1fr)", gap: 5, maxHeight: 200, overflowY: "auto", padding: 5 }}>
                    {levels.map(level => (
                      <button key={level.id} onClick={() => handleJoin(level.id)} style={{ padding: "8px 5px", borderRadius: 8, background: "#4CAF50", color: "white", border: "none", fontWeight: 800, cursor: "pointer", boxShadow: "0 2px 0 #388E3C" }}>
                        Lvl {level.id}
                      </button>
                    ))}
                  </div>
                </div>
              )}
            </>
          ) : (
            <div style={{ display: "flex", gap: 10, marginTop: 10 }}>
              <button onClick={() => handleJoin(null)} style={{ flex: 1, padding: 14, borderRadius: 12, background: "#FF9800", color: "white", border: "none", fontWeight: 800, cursor: "pointer", boxShadow: "0 4px 0 #F57C00", fontSize: 16 }}>Join Game ({room})</button>
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

function AlphabetGame() {
  const [user, setUser] = useState(null);
  const [game, setGame] = useState(null);
  const [dragItem, setDragItem] = useState(null);
  const [highlightSlot, setHighlightSlot] = useState(null);
  const [introPhase, setIntroPhase] = useState("idle");
  const [shakeSlot, setShakeSlot] = useState(null);
  const [fallingLetter, setFallingLetter] = useState(null);
  const [copied, setCopied] = useState(false);

  useEffect(() => {
    if (!user) return;
    const poll = setInterval(async () => {
      const data = await safeFetch(`${API_URL}?action=state&room=${user.room}`);
      if (data.status !== "error") {
        setGame(prev => {
          if (data.phase === 'intro' && (!prev || prev.phase !== 'intro')) triggerIntroAnimation(data);
          return data;
        });
      }
    }, 1500);
    return () => clearInterval(poll);
  }, [user]);

  const prevPhaseRef = useRef(null);
  const prevWordIndexRef = useRef(null);

  useEffect(() => {
    if (!game || !user) return;

    // Auto-TTS for spelling mode when a new word appears in the intro or playing phase
    if (game.mode === 'spelling' && (game.phase === 'intro' || game.phase === 'playing') && game.words_list) {
      if (prevWordIndexRef.current !== game.current_word_index) {
        const currentWord = game.words_list[game.current_word_index]?.word;
        if (currentWord) {
          playTTS(currentWord);
          prevWordIndexRef.current = game.current_word_index;
        }
      }
    }

    // Handle sounds that trigger on state change
    if (prevPhaseRef.current !== game.phase && game.phase === 'word_complete') {
      playSound('correct sound.mp3');
    }
    if (prevPhaseRef.current !== 'game_over' && game.game_over) {
      playSound('end game.mp3');
    }
    prevPhaseRef.current = game.game_over ? 'game_over' : game.phase;

    if (game.phase === 'word_complete' && user.playerId === 0) {
      const timer = setTimeout(() => {
        safeFetch(`${API_URL}?action=next_word&room=${user.room}`);
      }, 4000);
      return () => clearTimeout(timer);
    }
  }, [game?.phase, game?.game_over, game?.current_word_index, user?.playerId, user?.room]);

  const triggerIntroAnimation = async (data) => {
    playSound('start game.mp3');
    setIntroPhase("intro_showing");
    await new Promise(r => setTimeout(r, 2000));
    setIntroPhase("intro_shaking");
    await new Promise(r => setTimeout(r, 800));
    setIntroPhase("intro_falling");
    await new Promise(r => setTimeout(r, 1500));
    setIntroPhase("idle");
    await safeFetch(`${API_URL}?action=start_playing&room=${user.room}`);
  };

  // --- Unified Pointer Events ---
  const handlePointerDown = (e, letter, index) => {
    if (!game || game.turn_index !== user.playerId || game.phase !== 'playing') return;
    setDragItem({ letter, index, x: e.clientX, y: e.clientY });
    const el = e.currentTarget;
    el.setPointerCapture(e.pointerId);
  };

  const handlePointerMove = (e) => {
    if (!dragItem) return;
    setDragItem(prev => ({ ...prev, x: e.clientX, y: e.clientY }));

    // Find closest slot within leniency radius
    const slots = document.querySelectorAll('.slot');
    let closestSlot = null;
    let minDistance = 60; // Leniency radius in pixels (very forgiving)

    slots.forEach(slot => {
      const rect = slot.getBoundingClientRect();
      const slotCenterX = rect.left + rect.width / 2;
      const slotCenterY = rect.top + rect.height / 2;
      const dist = Math.hypot(slotCenterX - e.clientX, slotCenterY - e.clientY);

      if (dist < minDistance) {
        minDistance = dist;
        const slotIdx = slot.getAttribute("data-slot-idx");
        if (slotIdx !== null) closestSlot = parseInt(slotIdx);
      }
    });

    setHighlightSlot(closestSlot);
  };

  const handlePointerUp = async (e) => {
    if (!dragItem) return;
    const { letter, index, x, y } = dragItem;
    const targetSlot = highlightSlot;
    setDragItem(null); setHighlightSlot(null);
    if (targetSlot !== null && game.slots[targetSlot] === null) {
      const data = await safeFetch(`${API_URL}?action=move&room=${user.room}&letter=${letter}&slot_idx=${targetSlot}&tray_idx=${index}&player_id=${user.playerId}`);
      if (data.status === "ok") {
        setGame(data);
        const targetLetters = data.target_letters || ALPHABET;
        if (letter !== targetLetters[targetSlot]) {
          setFallingLetter({ letter, x, y });
          setTimeout(() => setFallingLetter(null), 1250);
          setShakeSlot(targetSlot);
          setTimeout(() => setShakeSlot(null), 800);
        } else {
          // It was correct
          if (game.mode !== 'spelling') {
            playSound('correct sound.mp3');
          }
        }
      }
    }
  };

  const handleHint = async () => {
    if (!game || game.turn_index !== user.playerId || game.phase !== 'playing') return;
    const data = await safeFetch(`${API_URL}?action=move&room=${user.room}&is_hint=true&player_id=${user.playerId}`);
    if (data.status === "ok") {
      setGame(data);
    }
  };

  const handleJoin = async (name, room) => {
    const data = await safeFetch(`${API_URL}?action=join&name=${encodeURIComponent(name)}&room=${room}`);
    if (data.player_id !== undefined) { setUser({ name, room, playerId: data.player_id }); window.history.pushState(null, "", "?room=" + room); }
    else alert(data.error);
  };

  if (!user) return <Lobby onJoin={handleJoin} />;
  if (!game) return <div style={{ background: "#5BB8F5", height: "100dvh" }} />;

  const myTurn = game.turn_index === user.playerId && game.phase === 'playing';
  const isIntro = introPhase !== "idle" || game.phase === 'intro';

  return (
    <div style={{
      width: "100%", height: "100dvh", position: "fixed", top: 0, left: 0,
      background: "linear-gradient(180deg,#A1DDFA 0%,#A2E9C2 100%)",
      display: "flex", flexDirection: "column", alignItems: "center", paddingBottom: "env(safe-area-inset-bottom, 20px)",
      overflow: "hidden", touchAction: "none", userSelect: "none", fontFamily: "'Fredoka', sans-serif"
    }}>
      <style>{`
        @keyframes fullShake { 0%,100%{transform:translate(0,0)} 15%{transform:translate(-4px,-3px)} 30%{transform:translate(4px,3px)} 45%{transform:translate(-4px,3px)} 60%{transform:translate(4px,-3px)} }
        @keyframes itemShake { 0%,100%{transform:translateX(0)} 25%{transform:translateX(-8px)} 75%{transform:translateX(8px)} }
        @keyframes letterFall { 0%{transform:translateY(0) rotate(0);opacity:1} 100%{transform:translateY(100vh) rotate(50deg);opacity:0} }
        @keyframes wrongLetterFall { 0%{transform:translate(0,0) rotate(0);} 15%{transform:translate(-10px,0) rotate(-10deg);} 30%{transform:translate(10px,0) rotate(10deg);} 45%{transform:translate(-10px,0) rotate(-10deg);} 60%{transform:translate(0,0) rotate(0);opacity:1;} 100%{transform:translateY(100vh) rotate(50deg);opacity:0;} }
        @keyframes pop { 0%{transform:scale(1)} 50%{transform:scale(1.2)} 100%{transform:scale(1)} }
        .full-shake { animation: fullShake 0.4s infinite; }
        .slot-shake { animation: itemShake 0.4s ease forwards; }
        .correct-pop { animation: pop 0.4s ease; transform-origin: center; }
        .letter-falling { animation: letterFall 0.75s ease-in forwards; pointer-events:none; }
        .wrong-letter-falling { animation: wrongLetterFall 1.25s ease-in forwards; pointer-events:none; }
        .slot { width:clamp(36px, 9vmin, 68px); height:clamp(36px, 9vmin, 68px); border:2px dashed rgba(255,255,255,0.3); border-radius:10px; transition:0.15s; background:rgba(255,255,255,0.06); }
        .slot.highlight { border-color:#4CAF50; background:rgba(255,255,255,0.2); transform:scale(1.1); z-index:10; }
        .block { display:flex; align-items:center; justify-content:center; color:white; font-weight:900; border-radius:12px; border:1px solid rgba(255,255,255,0.3); touch-action:none; }
      `}</style>

      <Cloud x={3} y={8} scale={1.2} speed={5} />
      <Cloud x={75} y={15} scale={1.4} speed={7} />
      <Star x={20} y={25} size={30} delay={0} />
      <Star x={85} y={10} size={25} delay={1} />
      <Star x={12} y={65} size={20} delay={0.5} />
      <Star x={78} y={55} size={35} delay={1.5} />

      {/* Balloons move dynamically out of the way when the user drags a letter */}
      {game.phase === 'playing' && <Balloons style={{ position: "absolute", left: "6vw", top: "15dvh", transform: "scale(0.8)" }} isPlaying={true} isDragging={!!dragItem} />}

      <div className={introPhase === "intro_shaking" ? "full-shake" : ""} style={{ width: "100%", maxWidth: 1200, display: "flex", flexDirection: "column", alignItems: "center", padding: "10px 5px", zIndex: 5 }}>
        {/* Header */}
        <div style={{ display: "flex", gap: 10, marginBottom: 8, justifyContent: "center", transform: (game.phase === 'playing' || game.phase === 'word_complete') ? "scale(1.15) translateY(5px)" : "scale(0.9)", transition: "all 0.4s ease", zIndex: 10 }}>
          <div style={{ background: "linear-gradient(#8D5B4C, #6A4135)", borderRadius: "8px", padding: "6px 18px", color: "white", fontWeight: 800, fontSize: 13, border: "3px solid #4D2D23", boxShadow: "0 4px 0 rgba(0,0,0,0.2), inset 0 2px 0 rgba(255,255,255,0.2)", position: "relative" }}>
            <div style={{ position: "absolute", top: -8, left: 15, width: 4, height: 10, background: "#ccc", borderRadius: 2 }}></div>
            <div style={{ position: "absolute", top: -8, right: 15, width: 4, height: 10, background: "#ccc", borderRadius: 2 }}></div>
            {user.room}
          </div>
          {game.players.map((p, i) => (
            <div key={i} style={{ background: i === game.turn_index ? "linear-gradient(#4CAF50, #2E7D32)" : "linear-gradient(#8D5B4C, #6A4135)", color: "white", padding: "6px 18px", borderRadius: "8px", fontSize: 13, fontWeight: 800, border: i === game.turn_index ? "3px solid #1B5E20" : "3px solid #4D2D23", boxShadow: "0 4px 0 rgba(0,0,0,0.2), inset 0 2px 0 rgba(255,255,255,0.2)", transition: "all 0.3s ease", position: "relative" }}>
              <div style={{ position: "absolute", top: -8, left: 15, width: 4, height: 10, background: "#ccc", borderRadius: 2 }}></div>
              <div style={{ position: "absolute", top: -8, right: 15, width: 4, height: 10, background: "#ccc", borderRadius: 2 }}></div>
              {p.name}: {p.score}
            </div>
          ))}
        </div>

        {/* Fancy Title fades entirely away during gameplay so it doesn't block the screen */}
        <div style={{ transform: "scale(0.65)", display: "flex", justifyContent: "center", marginBottom: (game.phase === 'lobby' || isIntro) ? -40 : 0, marginTop: (game.phase === 'lobby' || isIntro) ? -20 : 0, pointerEvents: "none", opacity: game.phase === 'lobby' || isIntro ? 1 : 0, transition: "all 0.6s ease", maxHeight: game.phase === 'lobby' || isIntro ? 400 : 0, overflow: "hidden" }}>
          <FancyTitle />
        </div>

        <MonkeyBubble visible={game.phase !== 'playing' && game.phase !== 'word_complete'} message={game.message} />

        {game.phase === 'lobby' && (
          <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 15, width: "100%", maxWidth: 280, alignItems: "center" }}>
            {user.playerId === 0 ? (
              <>
                <div style={{ color: "white", textAlign: "center" }}>
                  <div style={{ fontSize: 14, fontWeight: 600, opacity: 0.9 }}>Send this code to your friend:</div>
                  <div style={{ fontSize: 36, fontWeight: 900, background: "rgba(0,0,0,0.25)", padding: "5px 20px", borderRadius: 16, border: "2px solid rgba(255,255,255,0.4)", letterSpacing: 4, margin: "10px 0" }}>{user.room}</div>
                </div>
                <button onClick={() => {
                  const url = `${window.location.origin}${window.location.pathname}?room=${user.room}`;
                  const success = () => { setCopied(true); setTimeout(() => setCopied(false), 2000); };
                  if (navigator.clipboard && navigator.clipboard.writeText) {
                    navigator.clipboard.writeText(url).then(success).catch(() => alert("Failed to copy link."));
                  } else {
                    try {
                      const el = document.createElement('textarea');
                      el.value = url;
                      document.body.appendChild(el);
                      el.select();
                      document.execCommand('copy');
                      document.body.removeChild(el);
                      success();
                    } catch (err) {
                      alert("Copy failed. Please copy the URL manually.");
                    }
                  }
                }} style={{ width: "100%", padding: "12px 24px", fontSize: 15, background: copied ? "#4CAF50" : "#8BC34A", border: "none", borderRadius: 50, fontWeight: 800, color: "white", cursor: "pointer", boxShadow: `0 4px 0 ${copied ? "#388E3C" : "#689F38"}` }}>
                  {copied ? "✅ Copied!" : "📋 Copy Invite Link"}
                </button>
                <button onClick={() => safeFetch(`${API_URL}?action=start_intro&room=${user.room}`)} style={{ width: "100%", padding: "14px 30px", fontSize: 18, background: "#FFC107", border: "none", borderRadius: 50, fontWeight: 800, color: "#5D4037", cursor: "pointer", boxShadow: "0 5px 0 #FFA000" }}>START MISSION 🚀</button>
              </>
            ) : (
              <div style={{ color: "white", textAlign: "center", background: "rgba(0,0,0,0.2)", padding: "16px", borderRadius: 16, fontWeight: 800, fontSize: 16, border: "2px dashed rgba(255,255,255,0.3)" }}>
                Waiting for host to start game...
              </div>
            )}
          </div>
        )}

        {/* Board Grid */}

        {game.mode === 'spelling' && game.words_list && game.words_list[game.current_word_index] && (
          <div style={{ display: "flex", alignItems: "center", justifyContent: "center", gap: 15, marginBottom: 10 }}>
            <div style={{ color: "white", fontSize: 28, fontWeight: 900, textShadow: "0 2px 4px rgba(0,0,0,0.3)" }}>
              {game.words_list[game.current_word_index].japanese}
            </div>
            <button
              onClick={() => playTTS(game.words_list[game.current_word_index].word)}
              style={{
                background: "#4CAF50", border: "none", borderRadius: "50%", width: 44, height: 44,
                display: "flex", alignItems: "center", justifyContent: "center", cursor: "pointer",
                boxShadow: "0 4px 0 #388E3C", fontSize: 20
              }}
            >
              🔊
            </button>
          </div>
        )}

        <div style={{ display: "flex", flexDirection: "column", gap: 6, padding: 8, background: "rgba(255,255,255,0.12)", borderRadius: 20, backdropFilter: "blur(5px)", marginBottom: 10 }}>
          {(() => {
            const targetLetters = game.target_letters || ALPHABET;
            const totalSlots = targetLetters.length;
            // If spelling mode, calculate laylout dynamically based on word length
            const isSpelling = (game.mode === 'spelling');
            const layout = isSpelling ? [totalSlots] : ROW_LAYOUT;

            return layout.map((count, ri) => {
              const start = layout.slice(0, ri).reduce((a, b) => a + b, 0);
              return (
                <div key={ri} style={{ display: "flex", gap: 6, justifyContent: "center", flexWrap: "wrap", maxWidth: "95vw" }}>
                  {Array.from({ length: count }, (_, ci) => {
                    const si = start + ci;
                    if (si >= totalSlots) return null; // Safety check
                    const letter = game.slots[si];
                    const targetLetter = targetLetters[si];
                    const isHighlight = highlightSlot === si;
                    const isFalling = introPhase === "intro_falling";
                    const isShaking = shakeSlot === si;
                    return (
                      <div key={si} data-slot-idx={si} className={`slot ${(isHighlight && !isIntro) ? 'highlight' : ''} ${isShaking ? 'slot-shake' : ''}`} style={{ display: "flex", alignItems: "center", justifyContent: "center" }}>
                        {!letter && game.mode !== 'spelling' && <span style={{ color: "rgba(255,255,255,0.3)", fontWeight: 900, fontSize: 13 }}>{targetLetter}</span>}
                        {letter && (
                          <div className={`block correct-pop ${isFalling ? 'letter-falling' : ''}`} style={{ width: "92%", height: "92%", fontSize: clamp(16, 4, 28), background: (isIntro || letter === targetLetter) ? "#4CAF50" : "#E84B3A", boxShadow: `0 4px 0 ${darken((isIntro || letter === targetLetter) ? "#4CAF50" : "#E84B3A")}` }}>{letter}</div>
                        )}
                      </div>
                    );
                  })}
                </div>
              );
            });
          })()}
        </div>
      </div>

      <div style={{ display: "flex", gap: 10, alignItems: "center", marginBottom: 8 }}>
        {myTurn && game.players.length > 1 && <div style={{ background: "#FFC107", padding: "6px 16px", borderRadius: 50, fontWeight: 800, fontSize: 14, color: "#5D4037", boxShadow: "0 4px 0 #FFA000" }}>{game.mode === 'spelling' ? 'Your Turn to Spell!' : `Your Turn: ${game.moves_left} left`}</div>}
        {myTurn && game.mode === 'spelling' && (
          <button onClick={handleHint} style={{ background: "#E91E63", color: "white", padding: "8px 16px", borderRadius: 20, border: "none", fontWeight: 800, cursor: "pointer", boxShadow: "0 4px 0 #C2185B" }}>
            💡 Hint (-20 pts)
          </button>
        )}
      </div>

      {/* Shared Tray (Optimized for all 26) */}
      <div style={{
        marginTop: "auto", width: "100%", maxWidth: 1000, background: "#2E694D", borderRadius: "28px 28px 0 0",
        padding: "20px 15px calc(40px + env(safe-area-inset-bottom, 0px))", borderTop: "12px solid #23543D", borderLeft: "12px solid #23543D", borderRight: "12px solid #23543D",
        boxShadow: "inset 0 10px 20px rgba(0,0,0,0.15), 0 -5px 25px rgba(0,0,0,0.1)", zIndex: 10,
        maxHeight: "38dvh", overflowY: "auto", position: "relative"
      }}>
        <Toys />
        <div style={{ display: "flex", justifyContent: "center", gap: 8, flexWrap: "wrap", zIndex: 2, position: "relative" }}>
          {(game.tray || []).map((l, i) => {
            let alphaIdx = ALPHABET.indexOf(l);
            if (alphaIdx === -1) alphaIdx = 0; // fallback
            const style = FALLEN_STYLES[alphaIdx];
            const isDragging = dragItem?.index === i;
            return (
              <div key={`${l}-${i}`}
                onPointerDown={e => handlePointerDown(e, l, i)}
                onPointerMove={handlePointerMove}
                onPointerUp={handlePointerUp}
                onPointerCancel={handlePointerUp}
                className="block"
                style={{
                  width: clamp(44, 9, 64), height: clamp(44, 9, 64),
                  fontSize: clamp(20, 4.5, 30),
                  background: BLOCK_COLORS[alphaIdx],
                  boxShadow: `0 5px 0 ${darken(BLOCK_COLORS[alphaIdx])}`,
                  cursor: myTurn ? "grab" : "default",
                  opacity: (myTurn || isIntro) ? 1 : 0.6,
                  transform: isDragging ? "scale(1.15) rotate(5deg) scale(0)" : introPhase === "intro_falling" ? "scale(0)" : (game.mode === 'alphabet' ? `translate(${style.dx}px, ${style.dy}px) rotate(${style.rotate}deg) scale(${style.scale})` : `rotate(${style.spellingRotate}deg) translateY(${style.dy}px) scale(${style.scale})`),
                  transition: isDragging ? "none" : "transform 0.3s ease-out",
                  margin: "4px"
                }}>{l}</div>
            );
          })}
          {(game.tray || []).length === 0 && !game.game_over && game.phase === 'playing' && <div style={{ color: "white", fontSize: 18, fontWeight: 800 }}>WAITING...</div>}
        </div>
      </div>

      {/* Dragging Overlay */}
      {dragItem && (
        <div className="block" style={{
          position: "fixed", left: dragItem.x - 30, top: dragItem.y - 30,
          width: 60, height: 60, background: BLOCK_COLORS[ALPHABET.indexOf(dragItem.letter)],
          fontSize: 30, boxShadow: `0 15px 40px rgba(0,0,0,0.5)`, pointerEvents: "none",
          zIndex: 1000, opacity: 0.95, transform: "rotate(8deg) scale(1.1)"
        }}>{dragItem.letter}</div>
      )}

      {/* Falling Incorrect Letter Overlay */}
      {fallingLetter && (
        <div className="block wrong-letter-falling" style={{
          position: "fixed", left: fallingLetter.x - 30, top: fallingLetter.y - 30,
          width: 60, height: 60, background: BLOCK_COLORS[ALPHABET.indexOf(fallingLetter.letter)],
          fontSize: 30, boxShadow: `0 15px 40px rgba(0,0,0,0.5)`, pointerEvents: "none",
          zIndex: 1000, opacity: 0.95
        }}>{fallingLetter.letter}</div>
      )}

      {/* Word Complete Modal */}
      {game.phase === 'word_complete' && (
        <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.85)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 1500 }}>
          <div className="correct-pop" style={{ background: "white", padding: "40px 60px", borderRadius: 30, textAlign: "center", maxWidth: 500, width: "90%", border: "8px solid #4CAF50" }}>
            <h2 style={{ color: "#4CAF50", margin: "0 0 10px", fontSize: 48, fontWeight: 900, textTransform: "uppercase", letterSpacing: 4 }}>{game.words_list[game.current_word_index]?.word || game.words_list[game.current_word_index]}</h2>
            <div style={{ fontSize: 32, fontWeight: 800, color: "#333", marginBottom: 20 }}>{game.words_list[game.current_word_index]?.japanese}</div>
            <p style={{ color: "#666", fontSize: 20, fontWeight: 700, margin: 0 }}>
              {game.players.length > 1
                ? `Get ready ${game.players[game.turn_index]?.name}, your turn is next!`
                : "Get ready, next word is coming..."}
            </p>
          </div>
        </div>
      )}

      {/* Victory Modal */}
      {game.game_over && (
        <div style={{ position: "fixed", inset: 0, background: "rgba(0,0,0,0.85)", display: "flex", alignItems: "center", justifyContent: "center", zIndex: 2000 }}>
          <div style={{ background: "white", padding: 40, borderRadius: 30, textAlign: "center", maxWidth: 350, width: "90%" }}>
            <div style={{ fontSize: 60, margin: "0 0 10px" }}>👑</div>
            <h2 style={{ color: "#4CAF50", margin: 0, fontSize: 32 }}>Mission Complete!</h2>
            <p style={{ color: "#555", fontWeight: 700, margin: "15px 0" }}>{game.message}</p>

            <div style={{ marginBottom: 20, display: "flex", flexDirection: "column", gap: 6 }}>
              {[...game.players].sort((a, b) => b.score - a.score).map((p, i) => (
                <div key={i} style={{ display: "flex", justifyContent: "space-between", padding: "10px 15px", background: i === 0 ? "#FFC107" : "#f5f5f5", color: i === 0 ? "#5D4037" : "#333", borderRadius: 12, fontWeight: 800 }}>
                  <span>{i === 0 ? "🥇 " : ""}{p.name}</span>
                  <span>{p.score} pts</span>
                </div>
              ))}
            </div>

            <div style={{ display: "flex", gap: 10 }}>
              <button onClick={() => safeFetch(`${API_URL}?action=reset&room=${user.room}`)} style={{ flex: 1, padding: 15, background: "#4CAF50", color: "white", border: "none", borderRadius: 12, fontWeight: 800, cursor: "pointer", boxShadow: "0 5px 0 #2E7D32" }}>Reset</button>
              <button onClick={() => { window.location.reload() }} style={{ flex: 1, padding: 15, background: "#ddd", color: "#333", border: "none", borderRadius: 12, fontWeight: 800, cursor: "pointer", boxShadow: "0 5px 0 #999" }}>Exit</button>
            </div>
          </div>
        </div>
      )}
    </div>
  );
}

function clamp(min, v, max) {
  return `clamp(${min}px, ${v}vmin, ${max}px)`;
}

const rootElement = document.getElementById('root');
if (rootElement) ReactDOM.createRoot(rootElement).render(<AlphabetGame />);
