"use client";

import { useState, useCallback } from "react";
import { Card } from "@/components/ui/card";
import { ClientOnly } from "@/components/ui/client-only";
import { StepControls } from "./step-controls";
import { MathDisplay } from "@/components/math/math-display";

type Mode = "commutative" | "associative" | "distributive";
type Op = "+" | "-" | "\\times" | "\\div";

interface Step {
  label: string;
  math: string;
  match?: boolean; // colour the result green (holds) / red (fails)
}

const OP_META: Record<Op, { apply: (a: number, b: number) => number; commutative: boolean; associative: boolean; name: string }> = {
  "+": { apply: (a, b) => a + b, commutative: true, associative: true, name: "Addition" },
  "-": { apply: (a, b) => a - b, commutative: false, associative: false, name: "Subtraction" },
  "\\times": { apply: (a, b) => a * b, commutative: true, associative: true, name: "Multiplication" },
  "\\div": { apply: (a, b) => a / b, commutative: false, associative: false, name: "Division" },
};

function fmt(x: number): string {
  if (Number.isInteger(x)) return `${x}`;
  return `${parseFloat(x.toFixed(3))}`;
}

function buildCommutativeSteps(a: number, b: number, op: Op): Step[] {
  const meta = OP_META[op];
  const r1 = meta.apply(a, b);
  const r2 = meta.apply(b, a);
  const same = r1 === r2;
  return [
    {
      label: "Commutative law: does the ORDER of the numbers change the answer?",
      math: `${a} ${op} ${b} \\quad \\text{vs} \\quad ${b} ${op} ${a}`,
    },
    { label: `Work out the first order.`, math: `${a} ${op} ${b} = ${fmt(r1)}` },
    { label: `Now swap the order.`, math: `${b} ${op} ${a} = ${fmt(r2)}` },
    meta.commutative
      ? {
          label: `Same answer! ${meta.name} IS commutative — order does not matter.`,
          math: `a ${op} b = b ${op} a`,
          match: true,
        }
      : {
          label: same
            ? `They match here only because the numbers are special. In general, ${meta.name.toLowerCase()} is NOT commutative.`
            : `Different answers! ${meta.name} is NOT commutative — order matters.`,
          math: `a ${op} b \\neq b ${op} a`,
          match: false,
        },
  ];
}

function buildAssociativeSteps(a: number, b: number, c: number, op: Op): Step[] {
  const meta = OP_META[op];
  const left = meta.apply(meta.apply(a, b), c);
  const right = meta.apply(a, meta.apply(b, c));
  return [
    {
      label: "Associative law: does where we put the BRACKETS change the answer?",
      math: `(${a} ${op} ${b}) ${op} ${c} \\quad \\text{vs} \\quad ${a} ${op} (${b} ${op} ${c})`,
    },
    { label: "Do the brackets on the LEFT first.", math: `(${a} ${op} ${b}) ${op} ${c} = ${fmt(meta.apply(a, b))} ${op} ${c} = ${fmt(left)}` },
    { label: "Now do the brackets on the RIGHT first.", math: `${a} ${op} (${b} ${op} ${c}) = ${a} ${op} ${fmt(meta.apply(b, c))} = ${fmt(right)}` },
    meta.associative
      ? { label: `Same answer! ${meta.name} IS associative — the grouping does not matter.`, math: `(a ${op} b) ${op} c = a ${op} (b ${op} c)`, match: true }
      : { label: `Different answers! ${meta.name} is NOT associative — the grouping matters.`, math: `(a ${op} b) ${op} c \\neq a ${op} (b ${op} c)`, match: false },
  ];
}

function buildDistributiveSteps(a: number, b: number, c: number): Step[] {
  const inside = b + c;
  const answer = a * inside;
  return [
    { label: "Distributive law: a number outside a bracket multiplies EVERYTHING inside.", math: `${a} \\times (${b} + ${c})` },
    {
      label: `Multiply the ${a} by each number inside the bracket separately.`,
      math: `${a} \\times ${b} \\; + \\; ${a} \\times ${c}`,
    },
    { label: "Working the direct way: add inside the bracket first, then multiply.", math: `${a} \\times (${b} + ${c}) = ${a} \\times ${inside} = ${answer}` },
    { label: "Working the expanded way gives the same answer.", math: `${a * b} + ${a * c} = ${answer}`, match: true },
  ];
}

// ── Quick practice ───────────────────────────────────────────────────────────

interface PracticeQ {
  prompt: string;
  answer: number;
}

function randInt(min: number, max: number) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}

function makeQuestion(): PracticeQ {
  const roll = Math.floor(Math.random() * 4);
  if (roll === 0) {
    const a = randInt(2, 9), b = randInt(1, 9), c = randInt(1, 9);
    return { prompt: `Fill the blank:  ${a} × (${b} + ${c}) = ${a} × ${b} + ${a} × ▢`, answer: c };
  }
  if (roll === 1) {
    const a = randInt(3, 12), b = randInt(1, a - 1);
    return { prompt: `Subtraction is not commutative. What is ${a} − ${b}?`, answer: a - b };
  }
  if (roll === 2) {
    const a = randInt(2, 8), b = randInt(1, 6), c = randInt(1, 6);
    return { prompt: `Work out ${a} × (${b} + ${c})`, answer: a * (b + c) };
  }
  const a = randInt(2, 9), b = randInt(2, 9);
  return { prompt: `Multiplication is commutative, so ${a} × ${b} equals ${b} × ▢. What is ▢?`, answer: a };
}

function QuickPractice() {
  const [q, setQ] = useState<PracticeQ>(() => makeQuestion());
  const [val, setVal] = useState("");
  const [feedback, setFeedback] = useState<"correct" | "incorrect" | null>(null);
  const [score, setScore] = useState({ correct: 0, total: 0 });

  function check() {
    const parsed = parseInt(val, 10);
    if (isNaN(parsed)) return;
    const correct = parsed === q.answer;
    setFeedback(correct ? "correct" : "incorrect");
    setScore((s) => ({ correct: s.correct + (correct ? 1 : 0), total: s.total + 1 }));
  }

  function next() {
    setQ(makeQuestion());
    setVal("");
    setFeedback(null);
  }

  return (
    <Card className="space-y-4">
      <div className="flex items-center justify-between">
        <p className="text-xs font-bold uppercase tracking-wider text-unit-8">Quick Practice</p>
        <span className="rounded-full bg-unit-8-light px-3 py-1 text-xs font-bold text-unit-8-dark">
          {score.correct}/{score.total}
        </span>
      </div>
      <p className="text-center text-lg font-bold">{q.prompt}</p>
      <div className="flex flex-wrap items-center justify-center gap-3">
        <input
          type="number"
          value={val}
          onChange={(e) => {
            setVal(e.target.value);
            setFeedback(null);
          }}
          onKeyDown={(e) => {
            if (e.key === "Enter") {
              if (feedback !== null) next();
              else check();
            }
          }}
          className={`w-24 rounded-lg border-2 px-3 py-2 text-center text-xl font-bold outline-none transition-colors ${
            feedback === "correct"
              ? "border-correct bg-correct-light"
              : feedback === "incorrect"
                ? "border-incorrect bg-incorrect-light"
                : "border-border focus:border-unit-8"
          }`}
          placeholder="?"
          aria-label="Your answer"
        />
        {feedback === null ? (
          <button onClick={check} className="rounded-lg bg-unit-8 px-5 py-2.5 text-sm font-bold text-white hover:bg-unit-8-dark">
            Check
          </button>
        ) : (
          <button onClick={next} className="rounded-lg bg-foreground px-5 py-2.5 text-sm font-bold text-background hover:bg-foreground/80">
            Next →
          </button>
        )}
      </div>
      {feedback === "correct" && <p className="text-center text-sm font-bold text-correct">Correct!</p>}
      {feedback === "incorrect" && (
        <p className="text-center text-sm font-bold text-incorrect">Not quite — the answer is {q.answer}.</p>
      )}
    </Card>
  );
}

// ── Main explorer ────────────────────────────────────────────────────────────

export function NumberLawsExplorer() {
  const [mode, setMode] = useState<Mode>("commutative");
  const [op, setOp] = useState<Op>("+");
  const [a, setA] = useState("8");
  const [b, setB] = useState("3");
  const [c, setC] = useState("2");
  const [error, setError] = useState("");

  const [steps, setSteps] = useState<Step[] | null>(null);
  const [currentStep, setCurrentStep] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);

  const done = steps ? currentStep >= steps.length - 1 : false;

  const reset = useCallback(() => {
    setSteps(null);
    setCurrentStep(0);
    setIsPlaying(false);
  }, []);

  function switchMode(m: Mode) {
    setMode(m);
    setError("");
    // distributive is fixed to + inside; keep whatever op for the others
    reset();
  }

  const opChoices: Op[] = mode === "associative" ? ["+", "\\times", "-"] : ["+", "-", "\\times", "\\div"];

  function handleGo() {
    setError("");
    const na = parseInt(a, 10);
    const nb = parseInt(b, 10);
    const nc = parseInt(c, 10);
    if (isNaN(na) || isNaN(nb) || (mode !== "commutative" && isNaN(nc))) {
      return setError("Enter whole numbers in every box.");
    }
    const vals = mode === "commutative" ? [na, nb] : [na, nb, nc];
    if (vals.some((v) => Math.abs(v) > 50)) return setError("Keep the numbers between -50 and 50.");
    if ((op === "\\div") && (nb === 0 || (mode === "associative" && nc === 0))) {
      return setError("Cannot divide by zero — change the numbers.");
    }
    if (mode === "commutative") setSteps(buildCommutativeSteps(na, nb, op));
    else if (mode === "associative") setSteps(buildAssociativeSteps(na, nb, nc, op));
    else setSteps(buildDistributiveSteps(na, nb, nc));
    setCurrentStep(0);
    setIsPlaying(false);
  }

  const stepForward = useCallback(() => {
    if (!steps || currentStep >= steps.length - 1) return;
    setCurrentStep((s) => s + 1);
    if (currentStep + 1 >= steps.length - 1) setIsPlaying(false);
  }, [steps, currentStep]);

  const stepBack = useCallback(() => {
    if (currentStep <= 0) return;
    setCurrentStep((s) => s - 1);
  }, [currentStep]);

  const togglePlay = useCallback(() => setIsPlaying((p) => !p), []);

  const step = steps ? steps[currentStep] : null;
  const showThree = mode !== "commutative";
  const showOp = mode !== "distributive";

  const opLabel: Record<Op, string> = { "+": "+", "-": "−", "\\times": "×", "\\div": "÷" };

  return (
    <div className="space-y-4">
      {/* Mode toggle */}
      <div className="flex flex-wrap gap-2">
        {(["commutative", "associative", "distributive"] as Mode[]).map((m) => (
          <button
            key={m}
            onClick={() => switchMode(m)}
            className={`rounded-full border-2 px-4 py-2 text-sm font-semibold capitalize transition-colors ${
              mode === m
                ? "border-unit-8 bg-unit-8 text-white"
                : "border-unit-8/40 text-unit-8 hover:bg-unit-8-light"
            }`}
          >
            {m}
          </button>
        ))}
      </div>

      {/* Operation tabs */}
      {showOp && (
        <div className="flex flex-wrap gap-2">
          {opChoices.map((o) => (
            <button
              key={o}
              onClick={() => {
                setOp(o);
                reset();
              }}
              className={`h-10 w-12 rounded-full border-2 text-lg font-bold transition-colors ${
                op === o
                  ? "border-unit-8-dark bg-unit-8-dark text-white"
                  : "border-unit-8/30 text-unit-8-dark hover:bg-unit-8-light"
              }`}
            >
              {opLabel[o]}
            </button>
          ))}
        </div>
      )}

      {/* Input card */}
      <Card>
        <p className="mb-3 text-xs font-bold uppercase tracking-wider text-unit-8">
          {mode === "distributive" ? "Enter a, b and c for a × (b + c)" : showThree ? "Enter three numbers" : "Enter two numbers"}
        </p>
        <div className="flex flex-wrap items-center gap-3">
          <input type="number" value={a} onChange={(e) => setA(e.target.value)} className="w-20 rounded-lg border-2 border-border bg-surface px-3 py-2 text-center text-lg font-bold outline-none focus:border-unit-8" aria-label="a" />
          <input type="number" value={b} onChange={(e) => setB(e.target.value)} className="w-20 rounded-lg border-2 border-border bg-surface px-3 py-2 text-center text-lg font-bold outline-none focus:border-unit-8" aria-label="b" />
          {showThree && (
            <input type="number" value={c} onChange={(e) => setC(e.target.value)} className="w-20 rounded-lg border-2 border-border bg-surface px-3 py-2 text-center text-lg font-bold outline-none focus:border-unit-8" aria-label="c" />
          )}
          <button onClick={handleGo} className="rounded-lg bg-unit-8 px-6 py-2.5 text-sm font-bold text-white transition-colors hover:bg-unit-8-dark">
            Go →
          </button>
        </div>
        {error && <p className="mt-2 text-sm text-incorrect">{error}</p>}
      </Card>

      {/* Display card */}
      <Card className="flex min-h-[220px] flex-col items-center justify-center gap-4 p-6">
        {!step ? (
          <p className="text-muted/50">
            Enter numbers above and click <strong>Go</strong>
          </p>
        ) : (
          <>
            <p className="text-center text-sm font-medium text-muted">{step.label}</p>
            <MathDisplay
              math={step.math}
              className={`text-2xl ${step.match === true ? "text-correct" : step.match === false ? "text-incorrect" : ""}`}
            />
          </>
        )}
      </Card>

      {/* Controls */}
      <Card className="p-4">
        <StepControls
          currentStep={currentStep + 1}
          totalSteps={steps?.length ?? 0}
          isPlaying={isPlaying}
          onStepForward={stepForward}
          onStepBack={stepBack}
          onTogglePlay={togglePlay}
          onReset={reset}
          canStepForward={!!steps && !done}
          canStepBack={!!steps && currentStep > 0}
        />
      </Card>

      {/* Quick practice */}
      <ClientOnly fallback={<Card className="min-h-[220px]" />}>
        <QuickPractice />
      </ClientOnly>
    </div>
  );
}
