"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";
import { FractionInput } from "@/components/practice/fraction-input";
import { Fraction, lcm } from "@/lib/math/fractions";
import { checkFractionAnswer } from "@/lib/math/validation";

type Op = "+" | "-" | "\\times" | "\\div";

interface Step {
  label: string;
  math: string;
}

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

/** Wrap a negative operand in parentheses so "a + (-b)" reads clearly. */
function operand(f: Fraction): string {
  return f.n < 0 ? `\\left(${f.toSignedKatex()}\\right)` : f.toSignedKatex();
}

function signWord(f: Fraction): string {
  return f.n < 0 ? "negative" : "positive";
}

function buildAddSubtractSteps(a: Fraction, b: Fraction, op: "+" | "-"): Step[] {
  const opSym = op;
  const steps: Step[] = [
    {
      label: "Start with the expression.",
      math: `${a.toSignedKatex()} ${opSym} ${operand(b)}`,
    },
  ];

  const lcd = lcm(a.d, b.d);
  let an = a.n;
  let bn = b.n;
  if (a.d !== b.d) {
    an = a.n * (lcd / a.d);
    bn = b.n * (lcd / b.d);
    steps.push({
      label: `The denominators are different. Find the common denominator: the LCM of ${a.d} and ${b.d} is ${lcd}.`,
      math: `\\text{LCD} = ${lcd}`,
    });
    steps.push({
      label: "Rewrite both fractions over the common denominator (the sign travels with the numerator).",
      math: `${a.toSignedKatex()} = ${new Fraction(an, lcd).toSignedKatex()} \\quad ${b.toSignedKatex()} = ${new Fraction(bn, lcd).toSignedKatex()}`,
    });
  }

  const rawNum = op === "+" ? an + bn : an - bn;
  const bnShown = bn < 0 ? `\\left(${bn}\\right)` : `${bn}`;
  steps.push({
    label:
      op === "+"
        ? "Add the numerators using the integer rules, keeping the common denominator."
        : "Subtract the numerators using the integer rules (subtracting a negative adds), keeping the common denominator.",
    math: `\\frac{${an} ${opSym} ${bnShown}}{${lcd}} = \\frac{${rawNum}}{${lcd}}`,
  });

  const raw = new Fraction(rawNum, lcd);
  const result = raw.simplified();
  if (result.n !== raw.n || result.d !== raw.d) {
    steps.push({
      label: "Simplify to lowest terms.",
      math: `${raw.toSignedKatex()} = ${result.toSignedKatex()}`,
    });
  }

  steps.push({
    label: `The answer is ${result.n < 0 ? "negative" : "positive"}.`,
    math: `${a.toSignedKatex()} ${opSym} ${operand(b)} = ${result.toSignedKatex()}`,
  });

  return steps;
}

function buildMultiplyDivideSteps(a: Fraction, b: Fraction, op: "\\times" | "\\div"): Step[] {
  const steps: Step[] = [
    {
      label: "Start with the expression.",
      math: `${a.toSignedKatex()} ${op} ${operand(b)}`,
    },
  ];

  let working = b;
  if (op === "\\div") {
    working = new Fraction(b.d, b.n); // reciprocal keeps the sign
    steps.push({
      label: "Dividing by a fraction is the same as multiplying by its reciprocal — keep, change, flip.",
      math: `${a.toSignedKatex()} \\times ${operand(working)}`,
    });
  }

  const negatives = (a.n < 0 ? 1 : 0) + (working.n < 0 ? 1 : 0);
  const resultNegative = negatives % 2 === 1;
  steps.push({
    label: `Decide the sign: ${signWord(a)} and ${signWord(working)}. ${
      negatives === 1 ? "Different signs give a NEGATIVE answer." : "The signs match, so the answer is POSITIVE."
    }`,
    math: `(${a.n < 0 ? "-" : "+"}) \\times (${working.n < 0 ? "-" : "+"}) = (${resultNegative ? "-" : "+"})`,
  });

  const absNum = Math.abs(a.n) * Math.abs(working.n);
  const den = a.d * working.d;
  steps.push({
    label: "Multiply the numerators, multiply the denominators, then apply the sign.",
    math: `\\frac{${Math.abs(a.n)} \\times ${Math.abs(working.n)}}{${a.d} \\times ${working.d}} = ${new Fraction(resultNegative ? -absNum : absNum, den).toSignedKatex()}`,
  });

  const raw = new Fraction(resultNegative ? -absNum : absNum, den);
  const result = raw.simplified();
  if (result.n !== raw.n || result.d !== raw.d) {
    steps.push({
      label: "Simplify to lowest terms.",
      math: `${raw.toSignedKatex()} = ${result.toSignedKatex()}`,
    });
  }

  steps.push({
    label: "Final answer.",
    math: `${a.toSignedKatex()} ${op} ${operand(b)} = ${result.toSignedKatex()}`,
  });

  return steps;
}

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

function randInt(min: number, max: number) {
  return Math.floor(Math.random() * (max - min + 1)) + min;
}
/** A proper-fraction numerator with a random sign: magnitude 1..den-1. */
function properSigned(den: number): number {
  const mag = randInt(1, Math.max(1, den - 1));
  return Math.random() < 0.5 ? -mag : mag;
}

interface PracticeProblem {
  a: Fraction;
  b: Fraction;
  op: Op;
  answer: Fraction;
}

function makeProblem(): PracticeProblem {
  const op = (["+", "-", "\\times", "\\div"] as Op[])[randInt(0, 3)];
  const d1 = randInt(2, 6);
  const d2 = randInt(2, 6);
  let n1 = properSigned(d1);
  let n2 = properSigned(d2);
  // This is the negative-fractions topic — make sure at least one operand is negative.
  if (n1 > 0 && n2 > 0) {
    if (Math.random() < 0.5) n1 = -n1;
    else n2 = -n2;
  }
  const a = new Fraction(n1, d1);
  const b = new Fraction(n2, d2);
  let answer: Fraction;
  if (op === "+") answer = a.plus(b).simplified();
  else if (op === "-") answer = a.minus(b).simplified();
  else if (op === "\\times") answer = a.times(b).simplified();
  else answer = a.dividedBy(b).simplified();
  return { a, b, op, answer };
}

function QuickPractice() {
  const [problem, setProblem] = useState<PracticeProblem>(() => makeProblem());
  const [num, setNum] = useState("");
  const [den, setDen] = useState("");
  const [status, setStatus] = useState<"solved" | "unsimplified" | "wrong" | null>(null);
  const [score, setScore] = useState({ correct: 0, total: 0 });
  const [missed, setMissed] = useState(false);
  const [scored, setScored] = useState(false);

  function check() {
    const n = parseInt(num, 10);
    const d = parseInt(den, 10);
    if (isNaN(n) || isNaN(d)) return;
    const res = checkFractionAnswer(n, d, problem.answer.n, problem.answer.d);
    setStatus(res.status);
    if (res.status === "wrong") {
      setMissed(true);
    } else if (res.status === "solved" && !scored) {
      setScored(true);
      setScore((s) => ({ correct: s.correct + (missed ? 0 : 1), total: s.total + 1 }));
    }
  }

  function next() {
    setProblem(makeProblem());
    setNum("");
    setDen("");
    setStatus(null);
    setMissed(false);
    setScored(false);
  }

  return (
    <Card className="space-y-4">
      <div className="flex items-center justify-between">
        <p className="text-xs font-bold uppercase tracking-wider text-unit-5">Quick Practice</p>
        <span className="rounded-full bg-unit-5-light px-3 py-1 text-xs font-bold text-unit-5-dark">
          {score.correct}/{score.total}
        </span>
      </div>
      <p className="text-center text-sm text-muted">Work it out and give your answer in its simplest form.</p>
      <div className="flex flex-wrap items-center justify-center gap-3">
        <MathDisplay
          math={`${problem.a.toSignedKatex()} ${problem.op} ${problem.b.n < 0 ? `\\left(${problem.b.toSignedKatex()}\\right)` : problem.b.toSignedKatex()} =`}
          className="text-2xl"
        />
        <FractionInput
          numerator={num}
          denominator={den}
          onNumeratorChange={setNum}
          onDenominatorChange={setDen}
          onSubmit={status === "solved" ? next : check}
          disabled={status === "solved"}
        />
        {status === "solved" ? (
          <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>
        ) : (
          <button onClick={check} className="rounded-lg bg-unit-5 px-5 py-2.5 text-sm font-bold text-white hover:bg-unit-5-dark">
            Check
          </button>
        )}
      </div>
      {status === "solved" && <p className="text-center text-sm font-bold text-correct">Correct!</p>}
      {status === "unsimplified" && (
        <p className="text-center text-sm font-bold text-hint">Right value — now write it in its simplest form.</p>
      )}
      {status === "wrong" && (
        <p className="text-center text-sm font-bold text-incorrect">Not quite. Watch the signs, then try again.</p>
      )}
    </Card>
  );
}

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

export function NegativeFractionsExplorer() {
  const [op, setOp] = useState<Op>("+");
  const [n1, setN1] = useState("-1");
  const [d1, setD1] = useState("2");
  const [n2, setN2] = useState("3");
  const [d2, setD2] = useState("4");
  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 handleGo() {
    setError("");
    const pn1 = parseInt(n1, 10);
    const pd1 = parseInt(d1, 10);
    const pn2 = parseInt(n2, 10);
    const pd2 = parseInt(d2, 10);
    if ([pn1, pd1, pn2, pd2].some((v) => isNaN(v))) return setError("Fill in every box with a whole number.");
    if (pd1 === 0 || pd2 === 0) return setError("A denominator cannot be zero.");
    if ([pn1, pd1, pn2, pd2].some((v) => Math.abs(v) > 20)) return setError("Keep the numbers between -20 and 20.");
    if (op === "\\div" && pn2 === 0) return setError("You cannot divide by zero.");

    const a = new Fraction(pn1, pd1);
    const b = new Fraction(pn2, pd2);
    setSteps(
      op === "+" || op === "-"
        ? buildAddSubtractSteps(a, b, op)
        : buildMultiplyDivideSteps(a, b, op),
    );
    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 fieldClass =
    "w-16 rounded-lg border-2 border-border bg-surface px-2 py-1.5 text-center text-lg font-bold outline-none focus:border-unit-5";

  return (
    <div className="space-y-4">
      {/* Operation selector */}
      <div className="flex flex-wrap gap-2">
        {(["+", "-", "\\times", "\\div"] as Op[]).map((o) => (
          <button
            key={o}
            onClick={() => {
              setOp(o);
              reset();
            }}
            className={`h-11 w-14 rounded-full border-2 text-xl font-bold transition-colors ${
              op === o
                ? "border-unit-5 bg-unit-5 text-white"
                : "border-unit-5/40 text-unit-5 hover:bg-unit-5-light"
            }`}
            aria-label={OP_LABEL[o]}
          >
            {OP_LABEL[o]}
          </button>
        ))}
      </div>

      {/* Input card */}
      <Card>
        <p className="mb-3 text-xs font-bold uppercase tracking-wider text-unit-5">
          Enter two fractions (numerators can be negative)
        </p>
        <div className="flex flex-wrap items-center gap-4">
          <div className="inline-flex flex-col items-center gap-0.5">
            <input type="number" value={n1} onChange={(e) => setN1(e.target.value)} className={fieldClass} aria-label="First numerator" />
            <div className="h-0.5 w-16 bg-foreground" />
            <input type="number" value={d1} onChange={(e) => setD1(e.target.value)} className={fieldClass} aria-label="First denominator" />
          </div>
          <span className="text-2xl font-bold text-muted">{OP_LABEL[op]}</span>
          <div className="inline-flex flex-col items-center gap-0.5">
            <input type="number" value={n2} onChange={(e) => setN2(e.target.value)} className={fieldClass} aria-label="Second numerator" />
            <div className="h-0.5 w-16 bg-foreground" />
            <input type="number" value={d2} onChange={(e) => setD2(e.target.value)} className={fieldClass} aria-label="Second denominator" />
          </div>
          <button
            onClick={handleGo}
            className="rounded-lg bg-unit-5 px-6 py-2.5 text-sm font-bold text-white transition-colors hover:bg-unit-5-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 two fractions 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" />
          </>
        )}
      </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>
  );
}
