import { useEffect, useRef } from 'react';
import { useQuery } from '@tanstack/react-query';
import { Navigate, NavLink, useParams } from 'react-router';
import { toast } from 'sonner';
import { useClient } from 'hooks/useClient';
import { LEVELS, isLevel, type Level } from './levels';
/**
* The difficulty list — and the URL is what holds the choice.
*
* `/minesweeper/expert` rather than a channel or panel state, because it is exactly the kind of thing
* `docs/navigation-audit.md` calls addressable: it survives a refresh, it can be linked, and the replay
* panel reads it from the URL instead of having it passed across. Rows are real `NavLink`s, so cmd-click
* and middle-click behave and the active style comes from the router rather than a hand-rolled compare.
*
* The SIDE EFFECT hangs off the URL too. An effect on the selected level posts the difficulty, so
* arriving at `/minesweeper/expert` by any route — click, deep link, back button — leaves the game on
* expert. `POST /difficulty` verifies and is idempotent, so a repeat costs a round trip and changes
* nothing.
*/
export const LevelsPanel = () => {
const { section } = useParams();
const client = useClient();
// useClient() returns fresh verbs every render; a ref keeps the effect below from re-running forever.
const clientRef = useRef(client);
clientRef.current = client;
const selected = isLevel(section) ? section : null;
const { data: status } = useQuery({
queryKey: ['minesweeper', 'status'],
queryFn: () => client.get<{ difficulty: Level | null; running: boolean }>('/minesweeper/status'),
});
useEffect(() => {
if (!selected) return;
clientRef.current
.post('/minesweeper/difficulty', { level: selected })
.catch(() => toast.error(`Could not switch the game to ${selected}.`));
}, [selected]);
// After the hooks, never before: one guard canonicalising both the bare route and a bogus section.
// It waits for status so the URL lands on what the game IS rather than on a guess.
if (!selected) {
if (!status) return