"use client";

import { useState, useCallback, useRef, useEffect } from "react";
import { Card } from "@/components/ui/card";
import { StepControls } from "./step-controls";

type Mode = "toSF" | "toOrd";

interface DisplayState {
  digits: string[];
  decimalPos: number;
  initPos: number;
  targetPos: number;
  origPower: number;
}

function parseOrdinary(raw: string): { digits: string[]; decimalPos: number } {
  const s = raw.trim().replace(/[\s,]/g, "");
  if (s.startsWith("-")) throw new Error("Please enter a positive number.");
  if (!/^\d*\.?\d+$/.test(s) || s === "")
    throw new Error("Invalid number. Try something like 7438 or 0.0055");
  if (s.length > 16) throw new Error("Number too long (max 16 digits).");

  const dot = s.indexOf(".");
  if (dot === -1) {
    return { digits: s.split(""), decimalPos: s.length };
  }
  return {
    digits: (s.slice(0, dot) + s.slice(dot + 1)).split(""),
    decimalPos: dot,
  };
}

function firstNonZero(digits: string[]): number {
  return digits.findIndex((d) => d !== "0");
}

function sfTargetPos(digits: string[]): number {
  const i = firstNonZero(digits);
  return i === -1 ? 1 : i + 1;
}

function buildCoeff(sigDigs: string[]): string {
  if (sigDigs.length === 0) return "0";
  if (sigDigs.length === 1) return sigDigs[0] + ".0";
  const rest = sigDigs.slice(1).join("").replace(/0+$/, "") || "0";
  return sigDigs[0] + "." + rest;
}

function buildOrdinary(digits: string[], pos: number): string {
  let s: string;
  if (pos <= 0) {
    s = "0." + "0".repeat(-pos) + digits.join("");
  } else if (pos >= digits.length) {
    s = digits.join("") + "0".repeat(pos - digits.length);
  } else {
    s = digits.slice(0, pos).join("") + "." + digits.slice(pos).join("");
  }
  s = s.replace(/^0+(?=[1-9])/, "");
  if (s.startsWith(".")) s = "0" + s;
  if (s.includes(".")) s = s.replace(/\.?0+$/, "");
  return s || "0";
}

export function StandardFormExplorer() {
  const [mode, setMode] = useState<Mode>("toSF");
  const [ordinaryInput, setOrdinaryInput] = useState("");
  const [coeffInput, setCoeffInput] = useState("");
  const [powerInput, setPowerInput] = useState("");
  const [error, setError] = useState("");

  const [display, setDisplay] = useState<DisplayState | null>(null);
  const [currentPos, setCurrentPos] = useState(0);
  const [isPlaying, setIsPlaying] = useState(false);
  const [done, setDone] = useState(false);

  const numberRowRef = useRef<HTMLDivElement>(null);
  const dotRef = useRef<HTMLDivElement>(null);
  const [dotLeft, setDotLeft] = useState(0);
  const [dotAnimate, setDotAnimate] = useState(false);
  const [powerPop, setPowerPop] = useState(false);

  const totalSteps = display ? Math.abs(display.targetPos - display.initPos) : 0;
  const currentStep = display ? Math.abs(currentPos - display.initPos) : 0;

  const currentPower = display
    ? mode === "toSF"
      ? display.initPos - currentPos
      : display.origPower - (currentPos - display.initPos)
    : 0;

  // Position decimal dot
  const placeDot = useCallback(
    (animate: boolean) => {
      if (!numberRowRef.current || !display) return;
      const boxes = numberRowRef.current.querySelectorAll<HTMLDivElement>("[data-digit-box]");
      if (!boxes.length) return;

      let leftPx: number;
      const dp = currentPos;
      if (dp <= 0) {
        leftPx = boxes[0].offsetLeft - 6;
      } else if (dp >= boxes.length) {
        const last = boxes[boxes.length - 1];
        leftPx = last.offsetLeft + last.offsetWidth - 4;
      } else {
        const prev = boxes[dp - 1];
        const next = boxes[dp];
        leftPx = Math.round((prev.offsetLeft + prev.offsetWidth + next.offsetLeft) / 2);
      }

      setDotAnimate(animate);
      setDotLeft(leftPx);
    },
    [currentPos, display],
  );

  useEffect(() => {
    if (display) {
      requestAnimationFrame(() => {
        requestAnimationFrame(() => placeDot(true));
      });
    }
  }, [currentPos, display, placeDot]);

  // Initial placement without animation
  useEffect(() => {
    if (display) {
      requestAnimationFrame(() => {
        requestAnimationFrame(() => placeDot(false));
      });
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [display?.digits.join("")]);

  function initDisplay(digits: string[], start: number, target: number, origPower: number) {
    setIsPlaying(false);
    setDone(start === target);
    setDisplay({ digits, decimalPos: start, initPos: start, targetPos: target, origPower });
    setCurrentPos(start);
    setError("");
  }

  function handleConvertToSF() {
    setError("");
    try {
      const { digits, decimalPos } = parseOrdinary(ordinaryInput);
      const target = sfTargetPos(digits);
      initDisplay(digits, decimalPos, target, 0);
    } catch (e) {
      setError((e as Error).message);
    }
  }

  function handleConvertToOrd() {
    setError("");
    try {
      if (!coeffInput.trim()) throw new Error("Enter the coefficient A.");
      const n = parseInt(powerInput, 10);
      if (isNaN(n)) throw new Error("Enter the power n as a whole number.");
      if (Math.abs(n) > 12) throw new Error("Power too large for display (max ±12).");
      if (n === 0) throw new Error("Power is 0 — the number is already in ordinary form.");

      const { digits } = parseOrdinary(coeffInput);
      const A = parseFloat(coeffInput);
      if (isNaN(A) || A < 1 || A >= 10)
        throw new Error(`Coefficient must satisfy 1 ≤ A < 10 (got ${coeffInput}).`);

      const decimalPos = 1;
      const expandedDigits = [...digits];

      let startPos: number;
      let targetPos: number;
      if (n > 0) {
        targetPos = decimalPos + n;
        startPos = decimalPos;
        while (expandedDigits.length < targetPos) expandedDigits.push("0");
      } else {
        const absN = Math.abs(n);
        const zeros = Array(absN).fill("0");
        expandedDigits.unshift(...zeros);
        startPos = decimalPos + absN;
        targetPos = startPos + n;
      }

      initDisplay(expandedDigits, startPos, targetPos, n);
    } catch (e) {
      setError((e as Error).message);
    }
  }

  const stepForward = useCallback(() => {
    if (!display || currentPos === display.targetPos) return;
    const dir = display.targetPos > display.initPos ? 1 : -1;
    const nextPos = currentPos + dir;
    setCurrentPos(nextPos);
    setPowerPop(true);
    setTimeout(() => setPowerPop(false), 300);
    if (nextPos === display.targetPos) {
      setDone(true);
      setIsPlaying(false);
    }
  }, [display, currentPos]);

  const stepBack = useCallback(() => {
    if (!display || currentPos === display.initPos) return;
    if (done) setDone(false);
    const dir = display.targetPos > display.initPos ? -1 : 1;
    setCurrentPos((p) => p + dir);
    setPowerPop(true);
    setTimeout(() => setPowerPop(false), 300);
  }, [display, currentPos, done]);

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

  const reset = useCallback(() => {
    setIsPlaying(false);
    setDisplay(null);
    setDone(false);
    setError("");
  }, []);

  // Direction label
  const remaining = display ? display.targetPos - currentPos : 0;
  const dirText =
    !display || done || remaining === 0
      ? null
      : remaining < 0
        ? `← Moving left · ${Math.abs(remaining)} step${Math.abs(remaining) !== 1 ? "s" : ""} remaining`
        : `→ Moving right · ${remaining} step${remaining !== 1 ? "s" : ""} remaining`;

  // Result
  const fz = display ? firstNonZero(display.digits) : 0;

  return (
    <div className="space-y-4">
      {/* Mode Tabs */}
      <div className="flex gap-2">
        <button
          onClick={() => {
            setMode("toSF");
            reset();
          }}
          className={`rounded-full border-2 px-4 py-2 text-sm font-semibold transition-colors ${
            mode === "toSF"
              ? "border-unit-2 bg-unit-2 text-white"
              : "border-unit-2/40 text-unit-2 hover:bg-unit-2-light"
          }`}
        >
          Ordinary → Standard Form
        </button>
        <button
          onClick={() => {
            setMode("toOrd");
            reset();
          }}
          className={`rounded-full border-2 px-4 py-2 text-sm font-semibold transition-colors ${
            mode === "toOrd"
              ? "border-unit-2 bg-unit-2 text-white"
              : "border-unit-2/40 text-unit-2 hover:bg-unit-2-light"
          }`}
        >
          Standard Form → Ordinary
        </button>
      </div>

      {/* Input Card */}
      <Card>
        <p className="mb-3 text-xs font-bold uppercase tracking-wider text-unit-2">
          {mode === "toSF" ? "Enter an ordinary number" : "Enter a number in standard form  A × 10ⁿ"}
        </p>
        {mode === "toSF" ? (
          <div className="flex flex-wrap items-center gap-2.5">
            <input
              type="text"
              value={ordinaryInput}
              onChange={(e) => setOrdinaryInput(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && handleConvertToSF()}
              placeholder="e.g. 7438 or 0.0055"
              maxLength={18}
              autoComplete="off"
              className="max-w-[220px] rounded-lg border-2 border-border bg-surface px-3.5 py-2.5 text-lg font-medium outline-none transition-colors focus:border-unit-2"
            />
            <button
              onClick={handleConvertToSF}
              className="rounded-lg bg-unit-2 px-6 py-2.5 text-sm font-bold text-white transition-colors hover:bg-unit-2-dark"
            >
              Convert →
            </button>
          </div>
        ) : (
          <div className="flex flex-wrap items-center gap-2.5">
            <input
              type="text"
              value={coeffInput}
              onChange={(e) => setCoeffInput(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && handleConvertToOrd()}
              placeholder="A  e.g. 3.6"
              maxLength={12}
              autoComplete="off"
              className="max-w-[140px] rounded-lg border-2 border-border bg-surface px-3.5 py-2.5 text-lg font-medium outline-none transition-colors focus:border-unit-2"
            />
            <span className="text-lg font-semibold">
              × 10<sup>n</sup> where n =
            </span>
            <input
              type="number"
              value={powerInput}
              onChange={(e) => setPowerInput(e.target.value)}
              onKeyDown={(e) => e.key === "Enter" && handleConvertToOrd()}
              placeholder="e.g. 4 or −3"
              autoComplete="off"
              className="max-w-[110px] rounded-lg border-2 border-border bg-surface px-3.5 py-2.5 text-lg font-medium outline-none transition-colors focus:border-unit-2"
            />
            <button
              onClick={handleConvertToOrd}
              className="rounded-lg bg-unit-2 px-6 py-2.5 text-sm font-bold text-white transition-colors hover:bg-unit-2-dark"
            >
              Convert →
            </button>
          </div>
        )}
        {error && <p className="mt-2 text-sm text-incorrect">{error}</p>}
      </Card>

      {/* Display Card */}
      <Card className="flex min-h-[260px] flex-col items-center justify-center gap-3 p-6">
        {!display ? (
          <p className="text-muted/50">
            Enter a number above and click <strong>Convert</strong>
          </p>
        ) : (
          <>
            {/* Step info */}
            <p className="text-sm text-muted">
              {totalSteps === 0
                ? "Number is already in standard form position — power = 0"
                : `Step ${currentStep + 1} of ${totalSteps}`}
            </p>

            {/* Digit row */}
            <div className="overflow-x-auto max-sm:pb-2">
            <div ref={numberRowRef} className="relative inline-flex items-end gap-2.5 px-4 pb-7 pt-2">
              {display.digits.map((ch, i) => {
                const isLeadingZero = i < fz && fz !== -1;
                const isHighlight = i === display.targetPos - 1;
                return (
                  <div
                    key={i}
                    data-digit-box
                    className={`flex h-[88px] w-[68px] shrink-0 select-none items-center justify-center rounded-xl border-2 text-[3.2rem] font-bold transition-all duration-300 max-sm:h-[70px] max-sm:w-[52px] max-sm:text-[2.4rem] ${
                      isLeadingZero
                        ? "border-border/60 bg-background text-muted/30"
                        : isHighlight
                          ? "border-unit-2 bg-unit-2-light text-foreground"
                          : "border-border bg-surface text-foreground"
                    }`}
                  >
                    {ch}
                  </div>
                );
              })}
              {/* Decimal dot */}
              <div
                ref={dotRef}
                className="absolute bottom-1.5 z-10 h-[18px] w-[18px] -translate-x-1/2 rounded-full bg-incorrect shadow-[0_2px_8px_rgba(239,68,68,0.45)]"
                style={{
                  left: dotLeft,
                  transition: dotAnimate ? "left 0.52s cubic-bezier(0.34,1.56,0.64,1), opacity 0.3s" : "none",
                  opacity: done && currentPos >= display.digits.length ? 0 : 1,
                }}
              />
            </div>
            </div>

            {/* Direction label */}
            {dirText && (
              <p
                className={`text-sm font-semibold ${
                  remaining < 0 ? "text-incorrect" : "text-hint"
                }`}
              >
                {dirText}
              </p>
            )}

            {/* Power counter */}
            <div className="flex items-baseline gap-1.5 text-2xl text-muted">
              <span>×</span>
              <span className="font-bold text-foreground">10</span>
              <sup
                className={`inline-block min-w-[38px] text-2xl font-extrabold text-hint ${
                  powerPop ? "animate-bounce" : ""
                }`}
              >
                {currentPower}
              </sup>
            </div>
          </>
        )}
      </Card>

      {/* Controls */}
      <Card className="p-4">
        <StepControls
          currentStep={currentStep + 1}
          totalSteps={totalSteps}
          isPlaying={isPlaying}
          onStepForward={stepForward}
          onStepBack={stepBack}
          onTogglePlay={togglePlay}
          onReset={reset}
          canStepForward={!!display && currentPos !== display.targetPos}
          canStepBack={!!display && currentPos !== display.initPos}
        />
      </Card>

      {/* Result Card */}
      <Card className="flex min-h-[90px] flex-col items-center justify-center gap-1.5 text-center">
        {!display || !done ? (
          <p className="text-sm text-muted/40">Result will appear here when steps are complete</p>
        ) : mode === "toSF" ? (
          <>
            <p className="text-xs uppercase tracking-wider text-muted">Standard Form</p>
            <p className="text-3xl font-extrabold max-sm:text-2xl">
              <span className="text-foreground">
                {buildCoeff(display.digits.slice(fz === -1 ? 0 : fz))}
              </span>
              <span className="mx-2 text-muted">×</span>
              <span className="text-foreground">10</span>
              <sup className="text-xl text-incorrect">{display.initPos - display.targetPos}</sup>
            </p>
          </>
        ) : (
          <>
            <p className="text-xs uppercase tracking-wider text-muted">Ordinary Form</p>
            <p className="text-3xl font-extrabold text-foreground max-sm:text-2xl">
              {buildOrdinary(display.digits, display.targetPos)}
            </p>
          </>
        )}
      </Card>
    </div>
  );
}
