// Shared UI primitives and feedback card

const useState = React.useState;
const useEffect = React.useEffect;
const useMemo = React.useMemo;
const useRef = React.useRef;

function Feedback({ state, correct, explain }) {
  // state: null | 'correct' | 'wrong'
  if (!state) return null;
  const ok = state === "correct";
  return (
    <div className={"fb " + (ok ? "fb-ok" : "fb-no")}>
      <div className="fb-icon">{ok ? "◯" : "✕"}</div>
      <div className="fb-body">
        <div className="fb-title">{ok ? "Correct!" : "Not quite"}</div>
        {!ok && correct && <div className="fb-ans"><b>正解：</b>{correct}</div>}
        {explain && <div className="fb-ex">{explain}</div>}
      </div>
    </div>
  );
}

function ProgressDots({ total, current }) {
  return (
    <div className="dots">
      {Array.from({ length: total }, (_, i) => (
        <span key={i} className={"dot" + (i < current ? " done" : "") + (i === current ? " cur" : "")}></span>
      ))}
    </div>
  );
}

function Btn({ children, onClick, variant = "primary", disabled, as, href }) {
  const cls = `btn btn-${variant}` + (disabled ? " is-disabled" : "");
  if (as === "a") return <a className={cls} href={href}>{children}</a>;
  return <button className={cls} onClick={onClick} disabled={disabled}>{children}</button>;
}

function normalizeAns(s) {
  return (s || "").toLowerCase().replace(/[.,!?;:"']/g, "").replace(/\s+/g, " ").trim();
}

function fuzzyMatch(user, correct) {
  const u = normalizeAns(user), c = normalizeAns(correct);
  if (!u) return false;
  if (u === c) return true;
  // allow small diff (one missing char) for short answers
  if (c.length < 40 && Math.abs(u.length - c.length) <= 1) {
    let diff = 0;
    const len = Math.max(u.length, c.length);
    for (let i = 0; i < len; i++) if ((u[i] || "") !== (c[i] || "")) diff++;
    return diff <= 2;
  }
  return false;
}

Object.assign(window, { Feedback, ProgressDots, Btn, normalizeAns, fuzzyMatch });
