"use client";
import Link from "next/link";
import { useEffect, useState } from "react";
import { flushSync } from "react-dom";
import StageIndicator from "@/components/game/StageIndicator";
import VariableChoiceAnswerForm from "@/components/game/VariableChoiceAnswerForm";
import VariableFeedbackPanel from "@/components/game/VariableFeedbackPanel";
import VariableScoreSummary from "@/components/game/VariableScoreSummary";
import KatexRenderer from "@/components/math/KatexRenderer";
import { formatVariableTermLatex } from "@/lib/engine/variable-parenthesis";
import type { VariableParenthesisProblem } from "@/lib/engine/variable-types";
import {
useVariableGameStore,
type VariableMaxTermCount,
type VariableProblemCount,
} from "@/store/variableGameStore";
const ACTIVE_TERM_COLOR = "#f97316";
function highlightLatex(latex: string) {
return `\\textcolor{${ACTIVE_TERM_COLOR}}{${latex}}`;
}
function formatActiveTermProblemLatex(
problem: VariableParenthesisProblem,
activeTermIndex: number,
) {
const termLatex = problem.terms
.map((term, index) => {
const displayTerm =
index === activeTermIndex
? highlightLatex(formatVariableTermLatex(term))
: formatVariableTermLatex(term);
if (index === 0) return displayTerm;
return `${problem.operators[index - 1]} ${displayTerm}`;
})
.join(" ");
return `${highlightLatex(`${problem.multiplier}`)}${highlightLatex(
"(",
)}${termLatex}${highlightLatex(")")}`;
}
interface VariablePlayClientProps {
problemCount: VariableProblemCount;
maxTermCount: VariableMaxTermCount;
}
export default function VariablePlayClient({
problemCount,
maxTermCount,
}: VariablePlayClientProps) {
const session = useVariableGameStore((state) => state.session);
const selectedProblemCount = useVariableGameStore(
(state) => state.selectedProblemCount,
);
const setProblemCount = useVariableGameStore(
(state) => state.setProblemCount,
);
const selectedMaxTermCount = useVariableGameStore(
(state) => state.selectedMaxTermCount,
);
const setMaxTermCount = useVariableGameStore(
(state) => state.setMaxTermCount,
);
const initSession = useVariableGameStore((state) => state.initSession);
const submitAnswer = useVariableGameStore((state) => state.submitAnswer);
const nextProblem = useVariableGameStore((state) => state.nextProblem);
const resetSession = useVariableGameStore((state) => state.resetSession);
const [selectedChoiceIds, setSelectedChoiceIds] = useState<(string | null)[]>(
() => Array.from({ length: maxTermCount }, () => null),
);
const [activeTermIndex, setActiveTermIndex] = useState(0);
const sessionProblemCount = session?.problems.length ?? null;
const currentProblem = session?.problems[session.currentIndex] ?? null;
const currentResult = session?.results[session.currentIndex] ?? null;
const isComplete = Boolean(
session && session.currentIndex >= session.problems.length,
);
const sessionNeedsInit =
sessionProblemCount !== problemCount || session?.termCount !== maxTermCount;
const correctCount =
session?.results.filter((result) => result?.correct).length ?? 0;
const totalCount = session?.problems.length ?? 0;
useEffect(() => {
if (selectedProblemCount !== problemCount) {
setProblemCount(problemCount);
}
if (selectedMaxTermCount !== maxTermCount) {
setMaxTermCount(maxTermCount);
}
if (sessionNeedsInit) {
initSession(problemCount, maxTermCount);
}
}, [
initSession,
maxTermCount,
problemCount,
selectedMaxTermCount,
selectedProblemCount,
sessionProblemCount,
sessionNeedsInit,
setMaxTermCount,
setProblemCount,
]);
useEffect(() => {
setSelectedChoiceIds(
Array.from({ length: currentProblem?.terms.length ?? maxTermCount }, () => null),
);
setActiveTermIndex(0);
}, [currentProblem?.key, currentProblem?.terms.length, maxTermCount]);
function handleSelectChoice(termIndex: number, choiceId: string) {
const nextSelectedChoiceIds = [...selectedChoiceIds];
nextSelectedChoiceIds[termIndex] = choiceId;
setSelectedChoiceIds(nextSelectedChoiceIds);
if (termIndex < nextSelectedChoiceIds.length - 1) {
setActiveTermIndex(termIndex + 1);
return;
}
if (currentResult || !currentProblem) return;
if (
nextSelectedChoiceIds.some((selectedChoiceId) => selectedChoiceId === null)
) {
return;
}
submitAnswer({ selectedChoiceIds: nextSelectedChoiceIds });
}
function handleNextProblem() {
flushSync(() => {
nextProblem();
});
}
if (!session || sessionNeedsInit) {
return (
);
}
if (isComplete) {
return (
);
}
if (!currentProblem) {
return (
);
}
const submitted = currentResult !== null;
const isLastProblem = session.currentIndex === session.problems.length - 1;
const problemLatex = submitted
? currentProblem.latexBefore
: formatActiveTermProblemLatex(currentProblem, activeTermIndex);
const pendingChoiceLabels = currentProblem.terms.map((term, index) =>
formatVariableTermLatex({
...term,
coefficient:
index > 0 && currentProblem.operators[index - 1] === "-"
? -term.coefficient
: term.coefficient,
}),
);
return (
{!submitted ? (
) : null}
{currentResult ? (
) : null}
);
}