import { motion } from "framer-motion";
import { useCallback, useEffect, useState } from "react";
import { apiGet, apiPost, apiUrl, type Status } from "../api";
import { useNfcWs } from "../NfcWsContext";
import { useToast } from "../toast";

export default function Capture() {
  const toast = useToast();
  const { log } = useNfcWs();
  const [st, setSt] = useState<Status | null>(null);

  const refresh = useCallback(() => {
    apiGet<Status>("/api/status")
      .then(setSt)
      .catch(() => {});
  }, []);

  useEffect(() => {
    refresh();
    const id = setInterval(refresh, 2000);
    return () => clearInterval(id);
  }, [refresh]);

  useEffect(() => {
    refresh();
  }, [log.length, refresh]);

  const lastEv = (() => {
    const c = [...log].reverse().find((e) => e.channel === "capture");
    if (!c) {
      return "";
    }
    return typeof c.payload === "object" ? JSON.stringify(c.payload) : String(c.payload);
  })();

  const sess = st?.session;
  const pct = sess ? Math.min(100, (sess.usedBytes / Math.max(1, sess.maxBytes)) * 100) : 0;

  const setDeep = async (enable: boolean) => {
    try {
      await apiPost("/api/session/deep", { enable });
      toast(
        enable ? "Passive read-all on (live scan on by default at boot)" : "Passive read-all off",
      );
      refresh();
    } catch (e) {
      toast(String(e), "err");
    }
  };

  const clearBuf = async () => {
    try {
      await apiPost("/api/session/clear", {});
      toast("Buffer cleared — scanning can resume");
      refresh();
    } catch (e) {
      toast(String(e), "err");
    }
  };

  const download = async () => {
    try {
      const r = await fetch(apiUrl("/api/session/export"));
      if (!r.ok) {
        throw new Error(await r.text());
      }
      const blob = await r.blob();
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `pn532-deep-capture-${Date.now()}.ndjson`;
      a.click();
      URL.revokeObjectURL(url);
      toast("Download started — check your Downloads folder");
    } catch (e) {
      toast(String(e), "err");
    }
  };

  return (
    <div className="space-y-6">
      <motion.div
        initial={{ opacity: 0, y: 10 }}
        animate={{ opacity: 1, y: 0 }}
        className="glass relative overflow-hidden p-8"
      >
        <div className="pointer-events-none absolute -left-20 top-0 h-48 w-48 rounded-full bg-bubble-mint/20 blur-3xl" />
        <h1 className="font-display text-3xl font-bold md:text-4xl">Passive read-all mode</h1>
        <p className="mt-1 text-sm font-medium text-bubble-mint/90">
          Same feature as “deep capture” — fully controlled from this screen.
        </p>
        <p className="mt-3 max-w-2xl text-slate-300">
          Turn it on below and keep <strong>live scan</strong> running (on by default at boot). Each{" "}
          <strong>new tag</strong> in the field is read <strong>passively</strong>: no per-block clicks — the
          firmware pulls <strong>all data it can</strong> (PN532 status + Classic sector/block dump with
          default keys, or Ultralight/NTAG page sweep). Results queue in <strong>device RAM</strong>; when
          full, polling pauses until you <strong>download</strong> and <strong>clear</strong>.
        </p>
      </motion.div>

      <div className="glass p-6">
        <div className="flex flex-wrap items-center justify-between gap-4">
          <div>
            <h2 className="font-display text-lg font-semibold">Read-all session buffer</h2>
            <p className="text-sm text-slate-400">
              {sess?.lines ?? 0} full dumps · {sess?.usedBytes ?? 0} / {sess?.maxBytes ?? "—"} bytes RAM
            </p>
          </div>
          <div className="flex flex-wrap gap-2">
            <button
              type="button"
              onClick={() => setDeep(!(sess?.deepCapture ?? false))}
              className={`rounded-2xl px-4 py-2 font-semibold ${
                sess?.deepCapture
                  ? "bg-bubble-mint/20 text-bubble-mint ring-2 ring-bubble-mint/40"
                  : "border border-white/15 bg-white/5"
              }`}
            >
              {sess?.deepCapture ? "Passive read-all ON" : "Enable passive read-all"}
            </button>
            <button
              type="button"
              onClick={download}
              className="rounded-2xl bg-gradient-to-r from-bubble-accent to-indigo-400 px-4 py-2 font-bold text-white shadow-glow"
            >
              Download NDJSON
            </button>
            <button type="button" onClick={clearBuf} className="rounded-2xl border border-white/20 px-4 py-2">
              Clear buffer
            </button>
          </div>
        </div>

        <div className="mt-6 h-4 overflow-hidden rounded-full bg-black/40">
          <motion.div
            className="h-full rounded-full bg-gradient-to-r from-bubble-accent to-bubble-mint"
            initial={false}
            animate={{ width: `${pct}%` }}
            transition={{ type: "spring", stiffness: 120, damping: 20 }}
          />
        </div>

        {sess?.full && (
          <div className="mt-6 rounded-2xl border-2 border-bubble-rose/50 bg-bubble-rose/10 p-4 text-center">
            <p className="font-display text-lg font-bold text-bubble-rose">Buffer full — reader paused</p>
            <p className="mt-1 text-sm text-slate-300">
              Tap <strong>Download NDJSON</strong> to pull every card profile to your phone, then{" "}
              <strong>Clear buffer</strong> to resume field scans.
            </p>
          </div>
        )}

        {sess?.deepCapture && st && !st.scanning && (
          <p className="mt-4 rounded-2xl border border-amber-500/30 bg-amber-500/10 p-3 text-sm text-amber-100">
            Firmware normally has <strong>Live scan</strong> on at boot. If you turned it off, enable it on the
            Dashboard.
          </p>
        )}

        {lastEv && (
          <pre className="mt-4 max-h-40 overflow-auto rounded-2xl border border-white/10 bg-black/30 p-3 text-xs text-slate-300">
            Last capture event: {lastEv}
          </pre>
        )}
      </div>
    </div>
  );
}
