// Main App component
function App() {
  const [user, setUser] = React.useState(() => loadUser());
  const [solves, setSolves] = React.useState(() => loadSolves());
  const [scramble, setScramble] = React.useState('');
  const [scrambleLoading, setScrambleLoading] = React.useState(false);
  const [btConnected, setBtConnected] = React.useState(false);
  const [btConnecting, setBtConnecting] = React.useState(false);
  const [cubeState, setCubeState] = React.useState(null);
  const btConnRef = React.useRef(null);

  // Puzzle + category state
  const [categories, setCategories] = React.useState(() => loadCategories());
  const [session, setSession] = React.useState(() => {
    const saved = loadSession();
    if (saved && WCA_PUZZLES.find(p => p.id === saved.puzzleId)) return saved;
    return { puzzleId: '333bf', categoryName: '3BLD' };
  });

  const activePuzzle = WCA_PUZZLES.find(p => p.id === session.puzzleId) || WCA_PUZZLES[2];
  const activeCats = categories[session.puzzleId] || activePuzzle.defaultCategories;
  const activeCategory = activeCats.includes(session.categoryName)
    ? session.categoryName : activeCats[0];

  // Filtered solves for active puzzle+category
  const filteredSolves = solves.filter(
    s => s.puzzleId === session.puzzleId && s.categoryName === activeCategory
  );

  function setSessionAndSave(next) {
    setSession(next);
    saveSession(next);
  }

  function handlePuzzleChange(puzzleId) {
    const cats = categories[puzzleId] || WCA_PUZZLES.find(p => p.id === puzzleId)?.defaultCategories || ['Full Solve'];
    const next = { puzzleId, categoryName: cats[0] };
    setSessionAndSave(next);
    newScramble(puzzleId);
  }

  function handleCategoryChange(categoryName) {
    setSessionAndSave({ ...session, categoryName });
  }

  function handleCategoriesChange(newCats) {
    const next = { ...categories, [session.puzzleId]: newCats };
    setCategories(next);
    saveCategories(next);
    // Keep active category valid
    if (!newCats.includes(activeCategory)) {
      setSessionAndSave({ ...session, categoryName: newCats[0] || '' });
    }
  }

  // Generate initial scramble
  React.useEffect(() => {
    newScramble(session.puzzleId);
    window._onNewScramble = () => newScramble(session.puzzleId);
    return () => { delete window._onNewScramble; };
  }, []);

  // Update keyboard shortcut when puzzle changes
  React.useEffect(() => {
    window._onNewScramble = () => newScramble(session.puzzleId);
  }, [session.puzzleId]);

  function newScramble(puzzleId) {
    const pid = puzzleId || session.puzzleId;
    const puzzle = WCA_PUZZLES.find(p => p.id === pid) || activePuzzle;
    setScrambleLoading(true);
    setTimeout(() => {
      if (window._cubingScramble) {
        window._cubingScramble(puzzle.scrambleEvent).then(s => {
          setScramble(s);
          setScrambleLoading(false);
        }).catch(() => {
          setScramble(generateScramble(puzzle.scrambleLen));
          setScrambleLoading(false);
        });
      } else {
        setScramble(generateScramble(puzzle.scrambleLen));
        setScrambleLoading(false);
      }
    }, 80);
  }

  function handleSolveComplete({ total, memo, exec, dnf, plusTwo }) {
    const solve = {
      id: Date.now(),
      at: Date.now(),
      puzzleId: session.puzzleId,
      categoryName: activeCategory,
      scramble,
      total,
      memo,
      exec,
      dnf: !!dnf,
      plusTwo: !!plusTwo,
    };
    const next = [...solves, solve];
    setSolves(next);
    saveSolves(next);
    newScramble(session.puzzleId);
  }

  function handleDelete(id) {
    const next = solves.filter(s => s.id !== id);
    setSolves(next);
    saveSolves(next);
  }

  function handleClear() {
    const label = `${activePuzzle.label} › ${activeCategory}`;
    if (window.confirm(`Delete all solves in "${label}"? This cannot be undone.`)) {
      const next = solves.filter(
        s => !(s.puzzleId === session.puzzleId && s.categoryName === activeCategory)
      );
      setSolves(next);
      saveSolves(next);
    }
  }

  // Bluetooth connect (GAN)
  async function handleBtConnect() {
    setBtConnecting(true);
    try {
      if (!window.ganWebBluetooth) throw new Error('GAN library not loaded');
      const conn = await window.ganWebBluetooth.connectGanCube();
      btConnRef.current = conn;
      conn.events$.subscribe(evt => {
        if (evt.type === 'FACELETS') {
          setCubeState({ solved: checkSolved(evt.facelets), facelets: evt.facelets });
        }
        if (evt.type === 'MOVE') {
          window.dispatchEvent(new CustomEvent('cube:move', { detail: evt }));
        }
      });
      await conn.sendCubeCommand({ type: 'REQUEST_FACELETS' });
      setBtConnected(true);
    } catch (err) {
      console.warn('BT connect failed:', err.message);
      alert('Could not connect to GAN cube.\n\nMake sure:\n• You\'re using Chrome/Edge on desktop\n• Bluetooth is enabled\n• Your GAN cube is turned on\n\nFalling back to manual timing mode.');
    }
    setBtConnecting(false);
  }

  function handleBtDisconnect() {
    if (btConnRef.current) {
      try { btConnRef.current.disconnect(); } catch {}
      btConnRef.current = null;
    }
    setBtConnected(false);
    setCubeState(null);
  }

  function checkSolved(facelets) {
    if (!facelets || facelets.length !== 54) return false;
    for (let f = 0; f < 6; f++) {
      const center = facelets[f * 9 + 4];
      for (let i = 0; i < 9; i++) {
        if (facelets[f * 9 + i] !== center) return false;
      }
    }
    return true;
  }

  function handleLogout() {
    saveUser(null);
    setUser(null);
  }

  if (!user) {
    return <Login onLogin={u => setUser(u)} />;
  }

  return (
    <div style={appStyles.root}>
      {/* Top nav */}
      <nav style={appStyles.nav}>
        <div style={appStyles.navLeft}>
          <span style={appStyles.navLogo}>⬛ blindth</span>
        </div>
        <div style={appStyles.navRight}>
          <span style={appStyles.navUser}>{user.name}</span>
          <button style={appStyles.navLogout} onClick={handleLogout}>Sign out</button>
        </div>
      </nav>

      {/* Puzzle + category selector bar */}
      <PuzzleSelector
        puzzleId={session.puzzleId}
        categoryName={activeCategory}
        categories={activeCats}
        onPuzzleChange={handlePuzzleChange}
        onCategoryChange={handleCategoryChange}
        onCategoriesChange={handleCategoriesChange}
      />

      {/* Main layout */}
      <main style={appStyles.main}>
        <div style={appStyles.leftCol}>
          {/* Bluetooth */}
          <BluetoothPanel
            connected={btConnected}
            connecting={btConnecting}
            onConnect={handleBtConnect}
            onDisconnect={handleBtDisconnect}
            cubeState={cubeState}
          />

          {/* Scramble */}
          <ScrambleDisplay
            scramble={scramble}
            loading={scrambleLoading}
            onNew={() => newScramble(session.puzzleId)}
          />

          {/* Timer */}
          <Timer
            onSolveComplete={handleSolveComplete}
            cubeConnected={btConnected}
          />

          {/* Stats — filtered to active puzzle+category */}
          {filteredSolves.length > 0 && <StatsBar solves={filteredSolves} />}
        </div>

        {/* Right column: history filtered to active puzzle+category */}
        <div style={appStyles.rightCol}>
          <div style={appStyles.historyHeader}>
            <span style={appStyles.historyTitle}>
              {activePuzzle.label}
              <span style={appStyles.historySep}>›</span>
              {activeCategory}
            </span>
            <span style={appStyles.historyCount}>{filteredSolves.length} solve{filteredSolves.length !== 1 ? 's' : ''}</span>
          </div>
          <HistoryPanel
            solves={filteredSolves}
            onDelete={handleDelete}
            onClear={handleClear}
          />
        </div>
      </main>
    </div>
  );
}

const appStyles = {
  root: {
    minHeight: '100vh',
    background: 'oklch(10% 0.01 250)',
    color: 'oklch(85% 0.01 250)',
    fontFamily: "'Inter', sans-serif",
    display: 'flex', flexDirection: 'column',
  },
  nav: {
    display: 'flex', alignItems: 'center', justifyContent: 'space-between',
    padding: '0 24px', height: '48px',
    borderBottom: '1px solid oklch(18% 0.01 250)',
    background: 'oklch(12% 0.01 250)',
    flexShrink: 0,
  },
  navLeft: { display: 'flex', alignItems: 'center', gap: '10px' },
  navLogo: {
    fontFamily: "'JetBrains Mono', monospace",
    fontSize: '16px', fontWeight: '700',
    color: 'oklch(88% 0.01 250)', letterSpacing: '-0.3px',
  },
  navRight: { display: 'flex', alignItems: 'center', gap: '14px' },
  navUser: { fontSize: '13px', color: 'oklch(50% 0.01 250)' },
  navLogout: {
    background: 'none', border: 'none', cursor: 'pointer',
    fontSize: '12px', color: 'oklch(38% 0.01 250)',
    fontFamily: "'Inter', sans-serif",
  },
  main: {
    flex: 1, display: 'flex', gap: '20px',
    padding: '20px 24px', maxWidth: '1200px',
    width: '100%', margin: '0 auto', boxSizing: 'border-box',
    alignItems: 'flex-start',
  },
  leftCol: {
    flex: '0 0 620px', display: 'flex', flexDirection: 'column', gap: '12px',
  },
  rightCol: {
    flex: 1, minWidth: 0, display: 'flex', flexDirection: 'column', gap: '8px',
  },
  historyHeader: {
    display: 'flex', alignItems: 'baseline', gap: '10px',
    padding: '0 2px',
  },
  historyTitle: {
    fontSize: '14px', fontWeight: '600', color: 'oklch(65% 0.01 250)',
    display: 'flex', alignItems: 'baseline', gap: '8px',
  },
  historySep: { color: 'oklch(35% 0.01 250)', fontWeight: '400' },
  historyCount: {
    fontSize: '12px', color: 'oklch(38% 0.01 250)', marginLeft: 'auto',
  },
};

const rootEl = document.getElementById('root');
const reactRoot = ReactDOM.createRoot(rootEl);
reactRoot.render(<App />);
