// Sign in (SD-0001 §5.2) — the single email + one-time-code flow behind both doors. Step 1
// requests a code; step 2 verifies it. Honest copy for every §5.2 state; storefront routing
// is handled by App on success. Visuals per the ui/designs export (hf-signin).
import { useEffect, useState } from "react";
import { requestCode, verifyCode, type ApiError, type VerifyResult } from "../api";
import { cooldownAppliesTo } from "../cooldown";
import CodeInput from "../ui/CodeInput";
import { AuthCard, Banner, Field, Footer, PrimaryButton, Screen, TopBar, Wordmark } from "../ui/kit";

type Door = "signup" | "login";

interface Props {
  door: Door;
  onAuthed: (result: VerifyResult) => void;
  onBack: () => void;
}

function useCooldown(): [number, (s: number) => void] {
  const [left, setLeft] = useState(0);
  const ticking = left > 0;
  useEffect(() => {
    if (!ticking) return;
    const t = setInterval(() => setLeft((v) => Math.max(0, v - 1)), 1000);
    return () => clearInterval(t);
  }, [ticking]);
  return [left, setLeft];
}

export default function SignIn({ door, onAuthed, onBack }: Props) {
  const [step, setStep] = useState<"email" | "code">("email");
  const [email, setEmail] = useState("");
  const [code, setCode] = useState("");
  const [busy, setBusy] = useState(false);
  const [fieldError, setFieldError] = useState<string | null>(null);
  const [codeError, setCodeError] = useState<string | null>(null);
  const [bannerError, setBannerError] = useState<ApiError | null>(null);
  const [cooldown, setCooldown] = useCooldown();
  // The address the running cooldown belongs to — the server's cooldown is per-address
  // (INV-3), so a different address must not be blocked by it (bug #20).
  const [cooldownFor, setCooldownFor] = useState<string | null>(null);

  function applyError(err: ApiError) {
    setFieldError(null);
    setCodeError(null);
    setBannerError(null);
    if (err.code === "invalid_email") setFieldError(err.message);
    else if (err.code === "resend_cooldown") setCooldown(err.retry_after_s ?? 60);
    else if (err.code === "code_mismatch" || err.code === "code_expired") setCodeError(err.message);
    else setBannerError(err); // delivery_failed, code_exhausted, unexpected
  }

  async function sendCode(): Promise<boolean> {
    setBusy(true);
    setFieldError(null);
    setBannerError(null);
    const err = await requestCode(email);
    setBusy(false);
    if (err) {
      applyError(err);
      if (err.code === "resend_cooldown") setCooldownFor(email);
      return err.code === "resend_cooldown"; // a cooldown still means a code is out there
    }
    setCooldown(60);
    setCooldownFor(email);
    return true;
  }

  async function submitEmail(e: React.FormEvent) {
    e.preventDefault();
    if (await sendCode()) {
      setCode("");
      setCodeError(null);
      setStep("code");
    }
  }

  async function resend() {
    setCodeError(null);
    setCode("");
    await sendCode();
  }

  async function submitCode(e: React.FormEvent) {
    e.preventDefault();
    setBusy(true);
    setCodeError(null);
    setBannerError(null);
    const res = await verifyCode(email, code);
    setBusy(false);
    if (!res.ok) {
      applyError(res.error);
      return;
    }
    onAuthed(res.result);
  }

  const heading = door === "signup" ? "Create your storefront" : "Log in";
  const sub =
    door === "signup"
      ? "Enter your email to begin. There's no password to create."
      : "Enter your email and we'll send a one-time code to sign in.";

  return (
    <Screen horizon>
      <TopBar
        left={<Wordmark size={22} />}
        right={
          <button type="button" className="lk lk--mute" onClick={onBack}>
            ← Back
          </button>
        }
      />
      <main className="screen__main">
        <AuthCard>
          {step === "email" ? (
            <form onSubmit={submitEmail} style={{ display: "contents" }}>
              <div>
                <h1>{heading}</h1>
                <p className="card__sub">{sub}</p>
              </div>
              {bannerError && (
                <Banner title="We couldn't send the code">
                  The email didn't go out. Try again in a moment — nothing was lost.
                </Banner>
              )}
              <Field
                label="Email"
                error={fieldError}
                inputProps={{
                  type: "email",
                  value: email,
                  placeholder: "you@example.com",
                  autoFocus: true,
                  required: true,
                  autoComplete: "email",
                  onChange: (ev) => setEmail(ev.target.value),
                }}
              />
              <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
                <PrimaryButton busy={busy} disabled={cooldownAppliesTo(email, cooldownFor, cooldown)}>
                  {busy
                    ? "Sending…"
                    : cooldownAppliesTo(email, cooldownFor, cooldown)
                      ? `Resend in ${cooldown}s`
                      : "Send code"}
                </PrimaryButton>
                <p className="note">
                  We'll email you a one-time code. That's all we need — no password, ever.
                </p>
              </div>
            </form>
          ) : (
            <form onSubmit={submitCode} style={{ display: "contents" }}>
              <div>
                <h1>Check your email</h1>
                <p className="card__sub">
                  We sent a 6-digit code to <span style={{ color: "var(--wv-starlight)" }}>{email}</span>.{" "}
                  <button type="button" className="lk" onClick={() => setStep("email")}>
                    Wrong address?
                  </button>
                </p>
              </div>
              {bannerError && (
                <Banner title={bannerError.code === "code_exhausted" ? "Too many attempts" : "Something went wrong"}>
                  {bannerError.code === "code_exhausted"
                    ? "That code is no longer valid. Request a fresh one to keep going."
                    : bannerError.message}
                </Banner>
              )}
              <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
                <CodeInput value={code} onChange={setCode} error={!!codeError} />
                {codeError && (
                  <p className="note note--attn" role="alert">
                    {codeError}
                  </p>
                )}
              </div>
              <div style={{ display: "flex", flexDirection: "column", gap: 12 }}>
                <PrimaryButton busy={busy}>{busy ? "Checking…" : "Continue"}</PrimaryButton>
                <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                  <p className="note">Good for 10 minutes.</p>
                  {cooldown > 0 ? (
                    <span className="note">Resend in {cooldown}s</span>
                  ) : (
                    <button type="button" className="lk" onClick={resend}>
                      Resend code
                    </button>
                  )}
                </div>
              </div>
            </form>
          )}
        </AuthCard>
      </main>
      <Footer />
    </Screen>
  );
}
