// Sign-in console — futuristic authentication boot screen.
// Identity verification, biometric scan, security clearance check.

function SignInConsole({ onAuthenticated, theme = "amber" }) {
  const loginGreeting = "Jarvis login terminal online. Secure authentication is ready. Please provide your operator credentials.";
  const [stage, setStage] = React.useState("idle"); // idle | scanning | verifying | granted | denied
  const [username, setUsername] = React.useState("");
  const [passphrase, setPassphrase] = React.useState("");
  const [biometric, setBiometric] = React.useState(0); // 0..1
  const [voiceEnabled, setVoiceEnabled] = React.useState(true);
  const [voiceStatus, setVoiceStatus] = React.useState("VOICE READY");
  const [logLines, setLogLines] = React.useState([
    { t: "00:00.001", k: "boot", m: "JARVIS Core v4.2.1 — initializing…" },
    { t: "00:00.034", k: "boot", m: "Secure channel established · AES-256-GCM" },
    { t: "00:00.082", k: "boot", m: "Awaiting operator credentials." },
  ]);
  const [pulseT, setPulseT] = React.useState(0);
  const canvasRef = React.useRef(null);
  const greetedRef = React.useRef(false);

  React.useEffect(() => {
    if (window.__JARVIS_LOGIN_ERROR) {
      pushLog("auth", "Access denied by server vault. Check operator handle/passphrase.");
    }
  }, []);

  React.useEffect(() => {
    if (!voiceEnabled || greetedRef.current) return;

    let cancelled = false;
    let playing = false;
    const speakOnce = async () => {
      if (cancelled || greetedRef.current) return;
      if (playing) return;
      playing = true;
      const ok = await speakJarvisLogin(loginGreeting, "login.mp3");
      playing = false;
      if (cancelled || greetedRef.current) return;
      if (ok) {
        greetedRef.current = true;
        setVoiceStatus("GREETING SENT");
        pushLog("boot", "Voice greeting transmitted.");
      } else {
        setVoiceStatus("CLICK OR TYPE TO ARM VOICE");
      }
    };

    const timer = setTimeout(speakOnce, 700);
    const unlock = () => {
      primeJarvisLoginAudio();
      speakOnce();
    };
    window.addEventListener("pointerdown", unlock, { once: true });
    window.addEventListener("keydown", unlock, { once: true });

    return () => {
      cancelled = true;
      clearTimeout(timer);
      window.removeEventListener("pointerdown", unlock);
      window.removeEventListener("keydown", unlock);
    };
  }, [voiceEnabled, loginGreeting]);

  // ambient pulse counter
  React.useEffect(() => {
    const id = setInterval(() => setPulseT(t => t + 1), 50);
    return () => clearInterval(id);
  }, []);

  // biometric scanner viz
  React.useEffect(() => {
    const c = canvasRef.current;
    if (!c) return;
    const ctx = c.getContext("2d");
    const dpr = Math.min(window.devicePixelRatio || 1, 2);
    let raf = 0;
    let t0 = performance.now();
    function resize() {
      const r = c.getBoundingClientRect();
      c.width = r.width * dpr;
      c.height = r.height * dpr;
    }
    resize();
    const ro = new ResizeObserver(resize);
    ro.observe(c);

    function tick() {
      const now = performance.now();
      const t = now - t0;
      const w = c.width, h = c.height;
      ctx.clearRect(0, 0, w, h);
      const cx = w / 2, cy = h / 2;
      const R = Math.min(w, h) * 0.4;

      // outer rings
      for (let i = 0; i < 4; i++) {
        ctx.beginPath();
        ctx.arc(cx, cy, R - i * 8 * dpr, 0, Math.PI * 2);
        ctx.strokeStyle = `rgba(255,179,71,${0.2 - i * 0.04})`;
        ctx.lineWidth = 1 * dpr;
        ctx.stroke();
      }

      // tick marks
      for (let i = 0; i < 60; i++) {
        const a = (i / 60) * Math.PI * 2;
        const isMaj = i % 5 === 0;
        ctx.beginPath();
        ctx.moveTo(cx + Math.cos(a) * R, cy + Math.sin(a) * R);
        ctx.lineTo(cx + Math.cos(a) * (R + (isMaj ? 8 : 4) * dpr), cy + Math.sin(a) * (R + (isMaj ? 8 : 4) * dpr));
        ctx.strokeStyle = isMaj ? "rgba(255,179,71,0.7)" : "rgba(255,179,71,0.3)";
        ctx.stroke();
      }

      // sweep arc
      const sweep = (t * 0.001) % (Math.PI * 2);
      ctx.beginPath();
      ctx.arc(cx, cy, R - 18 * dpr, sweep, sweep + 0.7);
      ctx.strokeStyle = "var(--primary)";
      ctx.strokeStyle = stage === "scanning" ? getCSS("--primary") : `rgba(255,179,71,0.5)`;
      ctx.lineWidth = 2 * dpr;
      ctx.stroke();

      // fingerprint-ish concentric arcs
      ctx.lineWidth = 1.4 * dpr;
      for (let i = 0; i < 8; i++) {
        const r = (R - 60 * dpr) * (0.3 + i * 0.09);
        const phase = i * 0.4 + Math.sin(t * 0.001 + i) * 0.3;
        ctx.beginPath();
        ctx.arc(cx, cy, r, phase, phase + Math.PI * 1.4);
        const op = stage === "scanning" ? 0.8 : 0.5;
        ctx.strokeStyle = `${getCSS("--primary")}${Math.floor(op * 255).toString(16).padStart(2, "0")}`;
        ctx.stroke();
      }

      // scanning bar
      if (stage === "scanning" || stage === "verifying") {
        const y = cy - R + ((t * 0.4) % (R * 2));
        ctx.beginPath();
        ctx.moveTo(cx - R, y);
        ctx.lineTo(cx + R, y);
        ctx.strokeStyle = getCSS("--hot");
        ctx.lineWidth = 1.5 * dpr;
        ctx.stroke();

        // glow band
        const grad = ctx.createLinearGradient(0, y - 30 * dpr, 0, y + 30 * dpr);
        grad.addColorStop(0, "rgba(255,94,58,0)");
        grad.addColorStop(0.5, "rgba(255,94,58,0.18)");
        grad.addColorStop(1, "rgba(255,94,58,0)");
        ctx.fillStyle = grad;
        ctx.fillRect(cx - R, y - 30 * dpr, R * 2, 60 * dpr);
      }

      raf = requestAnimationFrame(tick);
    }
    tick();
    return () => { cancelAnimationFrame(raf); ro.disconnect(); };
  }, [stage]);

  function getCSS(v) {
    return getComputedStyle(document.documentElement).getPropertyValue(v).trim() || "#ffb347";
  }

  function pushLog(k, m) {
    const d = new Date();
    const t = `${String(d.getMinutes()).padStart(2, "0")}:${String(d.getSeconds()).padStart(2, "0")}.${String(d.getMilliseconds()).padStart(3, "0")}`;
    setLogLines(ll => [...ll, { t, k, m }].slice(-12));
  }

  async function toggleLoginVoice() {
    if (voiceEnabled) {
      primeJarvisLoginAudio();
      const ok = await speakJarvisLogin(loginGreeting, "login.mp3");
      setVoiceStatus(ok ? "VOICE ONLINE" : "CLICK OR TYPE TO ARM VOICE");
      pushLog("boot", ok ? "Login voice link online." : "Voice link awaiting browser gesture.");
      return;
    }
    const next = !voiceEnabled;
    setVoiceEnabled(next);
    if (next) {
      greetedRef.current = false;
      const ok = await speakJarvisLogin("Login voice link online.");
      setVoiceStatus(ok ? "VOICE ONLINE" : "CLICK OR TYPE TO ARM VOICE");
      pushLog("boot", ok ? "Login voice link online." : "Voice link awaiting browser gesture.");
    } else {
      if ("speechSynthesis" in window) window.speechSynthesis.cancel();
      setVoiceStatus("VOICE MUTED");
      pushLog("boot", "Login voice muted.");
    }
  }

  async function serverLogin() {
    const res = await fetch(`${window.__JARVIS_BASE_PATH || ""}/api/auth/login`, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      credentials: "same-origin",
      body: JSON.stringify({
        username: username.trim(),
        password: passphrase,
      }),
    });
    let data = {};
    try {
      data = await res.json();
    } catch (e) {
      data = {};
    }
    if (!res.ok || !data.ok) {
      throw new Error(data.message || "Server rejected the operator credentials.");
    }
    return data;
  }

  async function authenticate(e) {
    if (e) e.preventDefault();
    if (!username.trim() || !passphrase.trim() || stage !== "idle") return;

    setStage("scanning");
    pushLog("auth", `Operator handle received: ${username.toUpperCase()}`);
    pushLog("auth", "Engaging biometric subsystem…");

    // animate biometric progress
    await animateProgress(setBiometric, 0, 1, 1600);

    setStage("verifying");
    pushLog("scan", "Biometric signature ✓ — match confidence 99.84%");
    await sleep(400);
    pushLog("crypto", "Cross-referencing identity vault…");
    await sleep(450);
    pushLog("crypto", "Submitting credentials to server vault.");
    try {
      const data = await serverLogin();
      pushLog("crypto", "Server vault accepted credential hash.");
      pushLog("auth", `Welcome back, ${(data.username || username).split(/\s+/)[0].toUpperCase()}.`);
      setStage("granted");
      await sleep(650);
      onAuthenticated && onAuthenticated({ username: data.username || username.trim() });
      window.location.assign(`${window.__JARVIS_BASE_PATH || ""}/`);
    } catch (err) {
      setStage("denied");
      pushLog("auth", err.message || "Access denied by server vault.");
      await sleep(1100);
      setBiometric(0);
      setPassphrase("");
      setStage("idle");
    }
  }

  function animateProgress(setter, from, to, ms) {
    return new Promise(resolve => {
      const start = performance.now();
      function step() {
        const t = Math.min(1, (performance.now() - start) / ms);
        setter(from + (to - from) * t);
        if (t < 1) requestAnimationFrame(step);
        else resolve();
      }
      step();
    });
  }
  function sleep(ms) { return new Promise(r => setTimeout(r, ms)); }

  const tagColor = (k) => ({
    boot: "var(--ink-2)",
    auth: "var(--primary)",
    scan: "var(--hot)",
    crypto: "var(--good)",
  }[k] || "var(--ink-2)");

  return (
    <div style={{
      position: "fixed", inset: 0,
      background: "var(--bg-0)",
      display: "flex", alignItems: "center", justifyContent: "center",
      zIndex: 100,
      fontFamily: "var(--font-ui)",
    }}>
      {/* Background grid */}
      <div className="bg-grid" style={{ position: "absolute", inset: 0, opacity: 0.6 }} />
      <div className="vignette" style={{ position: "absolute", inset: 0 }} />
      <div className="scanlines" style={{ position: "absolute", inset: 0 }} />

      {/* Header strip */}
      <div className="row between" style={{
        position: "absolute", top: 18, left: 18, right: 18,
      }}>
        <div className="row gap-md">
          <div style={{
            width: 14, height: 14,
            border: "1.5px solid var(--primary)",
            borderRadius: "50%",
            position: "relative",
          }}>
            <div style={{
              position: "absolute", inset: 2,
              background: "var(--primary)",
              borderRadius: "50%",
              boxShadow: "0 0 6px var(--primary)",
              animation: "pulse-dot 2s ease-in-out infinite",
            }} />
          </div>
          <span style={{
            fontFamily: "var(--font-mono)", fontSize: 14,
            letterSpacing: "0.32em", color: "var(--primary)", fontWeight: 500,
          }}>JARVIS</span>
          <span className="label" style={{ color: "var(--ink-3)" }}>v4.2.1 · BUILD 81F2</span>
        </div>
        <div className="row gap-md">
          <span className="label" style={{ color: "var(--ink-3)" }}>SECURE TERMINAL · NODE 0x7F2A</span>
          <span className="panel-status">UPLINK</span>
          <button
            type="button"
            className="label voice-toggle"
            onClick={toggleLoginVoice}
            title={voiceStatus}
          >
            {voiceEnabled ? "VOICE ON" : "VOICE OFF"}
          </button>
        </div>
      </div>

      {/* Bottom strip */}
      <div className="row between" style={{
        position: "absolute", bottom: 14, left: 18, right: 18,
      }}>
        <span className="label" style={{ color: "var(--ink-3)" }}>
          AUTHORIZED PERSONNEL ONLY · ALL ACCESS LOGGED
        </span>
        <span className="label" style={{ color: "var(--ink-3)" }}>
          ENC · AES-256-GCM &nbsp;·&nbsp; SIG · ED25519
        </span>
      </div>

      {/* Main console card */}
      <div className="glass signin-card" style={{
        width: "min(960px, 92vw)",
        height: "min(580px, 82vh)",
        display: "grid",
        gridTemplateColumns: "1.1fr 1fr",
        position: "relative",
        overflow: "hidden",
      }}>
        <div className="scanner" />

        {/* LEFT — credential entry */}
        <div className="col" style={{ padding: "32px 36px", borderRight: "1px solid var(--glass-line)", position: "relative" }}>
          <div className="col gap-sm" style={{ marginBottom: 28 }}>
            <span className="label">SECTION · 01 / 02</span>
            <h1 style={{
              margin: 0,
              fontFamily: "var(--font-mono)",
              fontSize: 28,
              letterSpacing: "0.18em",
              color: "var(--primary)",
              fontWeight: 500,
              textShadow: "0 0 16px rgba(255,179,71,0.25)",
            }}>IDENTITY · VERIFICATION</h1>
            <p style={{
              margin: 0, fontSize: 13, color: "var(--ink-2)", lineHeight: 1.6, maxWidth: 420,
            }}>
              Provide your operator handle and passphrase. Biometric signature will be captured automatically.
            </p>
          </div>

          <form onSubmit={authenticate} className="col gap-lg" style={{ flex: 1 }}>
            <Field
              label="Operator handle"
              tag="ID.001"
              value={username}
              onChange={setUsername}
              placeholder="e.g. T. Stark"
              disabled={stage !== "idle"}
              autoFocus
            />
            <Field
              label="Passphrase"
              tag="ID.002"
              value={passphrase}
              onChange={setPassphrase}
              placeholder="• • • • • • • • • • • •"
              type="password"
              disabled={stage !== "idle"}
            />

            <div className="col gap-sm" style={{ marginTop: 4 }}>
              <div className="row between">
                <span className="label">BIOMETRIC SIGNATURE</span>
                <span className="num" style={{
                  fontSize: 11,
                  color: stage === "granted" ? "var(--good)" : stage === "idle" ? "var(--ink-3)" : "var(--primary)",
                }}>
                  {stage === "idle" ? "AWAITING" : stage === "granted" ? "MATCH ✓" : `${Math.floor(biometric * 100)}%`}
                </span>
              </div>
              <div className="tele-bar">
                <div className="tele-bar-fill" style={{
                  width: `${biometric * 100}%`,
                  background: stage === "granted"
                    ? "var(--good)"
                    : "linear-gradient(90deg, var(--primary), var(--hot))",
                }} />
              </div>
            </div>

            <div className="row gap-md" style={{ marginTop: "auto" }}>
              <button
                type="submit"
                className="btn"
                disabled={stage !== "idle" || !username.trim() || !passphrase.trim()}
                style={{
                  flex: 1,
                  padding: "14px 18px",
                  fontSize: 11,
                  borderColor: stage === "granted" ? "var(--good)" : (username.trim() && passphrase.trim() ? "var(--primary)" : "var(--glass-line)"),
                  color: stage === "granted" ? "var(--good)" : (username.trim() && passphrase.trim() ? "var(--primary)" : "var(--ink-3)"),
                  background: stage === "granted" ? "rgba(124,255,176,0.08)" : "transparent",
                }}
              >
                {{
                  idle: "▸ AUTHENTICATE",
                  scanning: "⟳ SCANNING…",
                  verifying: "⟳ VERIFYING…",
                  granted: "✓ ACCESS GRANTED",
                  denied: "✕ ACCESS DENIED",
                }[stage]}
              </button>
              <button
                type="button"
                className="btn"
                disabled={stage !== "idle"}
                style={{ padding: "14px 18px" }}
              >
                ⎋ ABORT
              </button>
            </div>
          </form>

          <div style={{
            position: "absolute", bottom: 16, left: 36, right: 36,
            display: "flex", justifyContent: "space-between",
          }}>
            <span className="label" style={{ color: "var(--ink-3)" }}>SESSION · {String(Math.floor(pulseT / 20))}s</span>
            <span className="label" style={{ color: "var(--ink-3)" }}>ATTEMPT · 01 / 03</span>
          </div>
        </div>

        {/* RIGHT — scanner + log */}
        <div className="col" style={{ padding: "24px 28px", position: "relative" }}>
          <div className="row between" style={{ marginBottom: 8 }}>
            <span className="label">SECTION · 02 / 02</span>
            <span className="label">{stage === "granted" ? "VERIFIED" : "BIO.SCAN"}</span>
          </div>

          <div style={{
            flex: 1,
            position: "relative",
            border: "1px solid var(--glass-line)",
            display: "flex", alignItems: "center", justifyContent: "center",
            overflow: "hidden",
          }} className="signin-scanner">
            <canvas ref={canvasRef} style={{ position: "absolute", inset: 0, width: "100%", height: "100%" }} />
            {/* Center label */}
            <div style={{ position: "absolute", textAlign: "center" }}>
              <div className="label" style={{ color: "var(--ink-3)" }}>{stage === "granted" ? "VERIFIED" : "PLACE FINGER ON SENSOR"}</div>
              <div className="num" style={{
                fontSize: 22, color: stage === "granted" ? "var(--good)" : "var(--primary)",
                marginTop: 6,
                letterSpacing: "0.15em",
              }}>
                {stage === "granted" ? "✓ MATCH" : `${Math.floor(biometric * 100).toString().padStart(2, "0")}%`}
              </div>
            </div>
            {/* Corner ticks */}
            <span className="glass-corner-tl" />
            <span className="glass-corner-tr" />
            <span className="glass-corner-bl" />
            <span className="glass-corner-br" />
          </div>

          {/* Log */}
          <div className="col" style={{
            marginTop: 14,
            border: "1px solid var(--glass-line)",
            padding: "10px 12px",
            height: 130,
            background: "rgba(0,0,0,0.25)",
          }}>
            <div className="row between" style={{ marginBottom: 6 }}>
              <span className="label label-primary">SYS.LOG</span>
              <span className="label" style={{ color: "var(--ink-3)" }}>TAIL · LIVE</span>
            </div>
            <div className="col scroll" style={{ flex: 1, gap: 2, fontFamily: "var(--font-mono)", fontSize: 10.5 }}>
              {logLines.map((l, i) => (
                <div key={i} className="row gap-sm" style={{ alignItems: "baseline" }}>
                  <span style={{ color: "var(--ink-3)" }}>{l.t}</span>
                  <span style={{ color: tagColor(l.k), letterSpacing: "0.1em", textTransform: "uppercase", minWidth: 50 }}>[{l.k}]</span>
                  <span style={{ color: "var(--ink-1)" }}>{l.m}</span>
                </div>
              ))}
              {(stage === "scanning" || stage === "verifying") && (
                <div className="row gap-sm" style={{ alignItems: "baseline" }}>
                  <span className="caret" style={{ width: 5, height: 10 }} />
                </div>
              )}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function Field({ label, tag, value, onChange, placeholder, type = "text", disabled, autoFocus }) {
  const [focus, setFocus] = React.useState(false);
  return (
    <div className="col gap-sm">
      <div className="row between">
        <span className="label">{label}</span>
        <span className="label" style={{ color: "var(--ink-3)" }}>{tag}</span>
      </div>
      <div style={{
        border: `1px solid ${focus ? "var(--primary)" : "var(--glass-line)"}`,
        background: focus ? "rgba(255,179,71,0.05)" : "rgba(0,0,0,0.18)",
        display: "flex", alignItems: "center",
        transition: "all 0.15s ease",
      }}>
        <span style={{
          padding: "0 10px 0 14px",
          color: focus ? "var(--primary)" : "var(--ink-3)",
          fontFamily: "var(--font-mono)",
          fontSize: 14,
        }}>›</span>
        <input
          type={type}
          value={value}
          onChange={e => onChange(e.target.value)}
          placeholder={placeholder}
          disabled={disabled}
          autoFocus={autoFocus}
          onFocus={() => setFocus(true)}
          onBlur={() => setFocus(false)}
          style={{
            flex: 1,
            background: "transparent",
            border: "none",
            outline: "none",
            color: "var(--ink-0)",
            fontFamily: "var(--font-ui)",
            fontSize: 15,
            padding: "12px 14px 12px 0",
            caretColor: "var(--primary)",
            letterSpacing: type === "password" ? "0.2em" : "0",
          }}
        />
        <span className="label" style={{ paddingRight: 12, color: "var(--ink-3)" }}>{disabled ? "LOCKED" : focus ? "ACTIVE" : "READY"}</span>
      </div>
    </div>
  );
}

function jarvisLoginAudioUrl(clipName) {
  return `${window.__JARVIS_BASE_PATH || ""}/static/jarvis/audio/${clipName}`;
}

async function primeJarvisLoginAudio() {
  try {
    const audio = new Audio(jarvisLoginAudioUrl("login.mp3"));
    audio.preload = "auto";
    audio.muted = true;
    audio.volume = 0;
    await audio.play();
    audio.pause();
    audio.currentTime = 0;
  } catch {}
}

async function speakJarvisLogin(text, clipName = null) {
  if (!text && !clipName) return false;
  try {
    if ("speechSynthesis" in window) window.speechSynthesis.cancel();
    if (clipName) {
      const ok = await playJarvisLoginClip(clipName);
      if (ok) return true;
    }
    return await speakJarvisLoginText(text);
  } catch {
    return false;
  }
}

async function playJarvisLoginClip(clipName) {
  try {
    const audio = new Audio(jarvisLoginAudioUrl(clipName));
    audio.volume = 0.95;
    await audio.play();
    return true;
  } catch {
    return false;
  }
}

async function speakJarvisLoginText(text) {
  if (!("speechSynthesis" in window) || !text) return false;
  return await new Promise(resolve => {
    let done = false;
    let nudger = null;
    const finish = (ok) => {
      if (done) return;
      done = true;
      if (nudger) clearInterval(nudger);
      resolve(ok);
    };
    try {
      const utterance = new SpeechSynthesisUtterance(text);
      const voices = window.speechSynthesis.getVoices ? window.speechSynthesis.getVoices() : [];
      const preferred = voices.find(v => /guy|david|mark|daniel|google uk english male/i.test(v.name))
        || voices.find(v => /^en[-_]/i.test(v.lang || ""))
        || voices[0];
      if (preferred) utterance.voice = preferred;
      utterance.rate = 0.88;
      utterance.pitch = 0.8;
      utterance.volume = 0.9;
      utterance.onend = () => finish(true);
      utterance.onerror = () => finish(false);
      setTimeout(() => finish(true), 12000);
      window.speechSynthesis.speak(utterance);
      try { window.speechSynthesis.resume(); } catch {}
      nudger = setInterval(() => {
        try { window.speechSynthesis.resume(); } catch {}
      }, 350);
    } catch {
      finish(false);
    }
  });
}

window.SignInConsole = SignInConsole;
