import { motion } from "framer-motion";
import { useEffect, useState } from "react";
import { Link } from "react-router-dom";
import { apiPost, apiGet, type Status, type Tag } from "../api";
import { useNfcWs } from "../NfcWsContext";
import { useToast } from "../toast";
import {
  generalStatusHexLine,
  sakLabel,
  scanCheatLines,
  typeHintLabel,
  uidWithSeparators,
} from "../nfcUtils";
import HeroVisual from "../ui/HeroVisual";

export default function Dashboard() {
  const toast = useToast();
  const { lastTag, applyScanPoll } = useNfcWs();
  const [st, setSt] = useState<Status | null>(null);
  const [scan, setScan] = useState(true);

  const poll = () => {
    apiGet<Status>("/api/status")
      .then(setSt)
      .catch(() => toast("Status unreachable", "err"));
  };

  useEffect(() => {
    poll();
    const id = setInterval(poll, 3000);
    return () => clearInterval(id);
  }, [toast]);

  useEffect(() => {
    if (st && typeof st.scanning === "boolean") {
      setScan(st.scanning);
    }
  }, [st]);

  const toggleScan = async () => {
    try {
      await apiPost<{ enable: boolean }>("/api/nfc/scan", { enable: !scan });
      setScan(!scan);
      toast(scan ? "Continuous scan off" : "Continuous scan on");
    } catch (e) {
      toast(String(e), "err");
    }
  };

  const pollOnce = async () => {
    try {
      const j = await apiPost<{ present: boolean; tag?: Tag }>("/api/nfc/poll", {});
      if (j.present && j.tag) {
        applyScanPoll(true, j.tag);
        toast(`Tag ${j.tag.uid}`);
      } else {
        applyScanPoll(false);
        toast("No tag");
      }
    } catch (e) {
      toast(String(e), "err");
    }
  };

  return (
    <div className="space-y-8">
      <motion.div
        initial={{ opacity: 0, y: 16 }}
        animate={{ opacity: 1, y: 0 }}
        transition={{ duration: 0.5, ease: [0.22, 1, 0.36, 1] }}
        className="glass relative overflow-hidden p-6 md:p-10"
      >
        <div className="pointer-events-none absolute inset-0 bg-[conic-gradient(from_180deg_at_50%_120%,rgba(0,229,255,0.08),transparent_40%,rgba(255,42,109,0.06),transparent_70%)]" />
        <div className="relative grid gap-8 lg:grid-cols-[1fr_min(320px,40%)] lg:items-center">
          <div>
            <p className="font-mono text-[10px] font-bold tracking-[0.4em] text-bubble-accent/80">COMMAND_LAYER</p>
            <h1 className="font-display mt-2 text-3xl font-normal tracking-wide text-glow-matrix md:text-5xl">
              NFC <span className="text-bubble-accent">CONTROL</span>
            </h1>
            <p className="mt-3 max-w-xl text-sm leading-relaxed text-slate-400">
              Full-time scan out of the box. Fat RF retries. Browser log + device session export — crank it from
              your phone.
            </p>
            {st?.session && (st.session.deepCapture || st.session.usedBytes > 0) && (
              <motion.div
                initial={{ opacity: 0, scale: 0.98 }}
                animate={{ opacity: 1, scale: 1 }}
                className="mt-5 flex flex-wrap items-center gap-3 rounded-xl border border-bubble-accent/40 bg-gradient-to-r from-bubble-accent/15 to-bubble-mint/10 px-4 py-3 text-sm shadow-glowCyan"
              >
                <span className="font-mono text-bubble-mint">
                  RAM {st.session.usedBytes}/{st.session.maxBytes}
                  {st.session.full ? " · LOCKED" : ""}
                </span>
                <Link
                  to="/capture"
                  className="btn-neon rounded-lg bg-bubble-mint/20 px-3 py-1 text-xs font-bold text-bubble-mint"
                >
                  Read-all →
                </Link>
              </motion.div>
            )}
            <div className="mt-8 flex flex-wrap gap-3">
              <motion.button
                type="button"
                whileHover={{ scale: 1.04 }}
                whileTap={{ scale: 0.98 }}
                onClick={pollOnce}
                className="btn-neon rounded-xl bg-gradient-to-r from-bubble-accent via-cyan-400 to-bubble-mint px-6 py-3 text-sm font-black uppercase tracking-wider text-bubble-950 shadow-neonBtn"
              >
                Poll tag
              </motion.button>
              <motion.button
                type="button"
                whileHover={{ scale: 1.03 }}
                whileTap={{ scale: 0.98 }}
                onClick={toggleScan}
                className={`rounded-xl border-2 px-6 py-3 text-sm font-bold uppercase tracking-wide transition ${
                  scan
                    ? "border-bubble-mint/70 bg-bubble-mint/15 text-glow-matrix text-bubble-mint shadow-glow"
                    : "border-white/20 bg-black/30 text-slate-400 hover:border-bubble-accent/50 hover:text-bubble-accent"
                }`}
              >
                {scan ? "Stop scan" : "Start scan"}
              </motion.button>
            </div>
          </div>
          <div className="relative flex justify-center lg:justify-end">
            <div className="relative w-full max-w-[280px] opacity-90 drop-shadow-[0_0_40px_rgba(0,229,255,0.35)]">
              <HeroVisual />
            </div>
          </div>
        </div>
      </motion.div>

      <div className="grid gap-5 md:grid-cols-2">
        <motion.div
          initial={{ opacity: 0, y: 12 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ delay: 0.08 }}
          className="glass p-6"
        >
          <h2 className="font-display text-lg font-normal text-bubble-accent text-glow-cyan">Device stack</h2>
          {st ? (
            <ul className="mt-4 space-y-3 font-mono text-sm text-slate-300">
              <li className="flex justify-between border-b border-white/5 pb-2">
                <span className="text-slate-500">uptime</span>
                <span className="text-bubble-mint">{(st.uptimeMs / 1000).toFixed(1)}s</span>
              </li>
              <li className="flex justify-between border-b border-white/5 pb-2">
                <span className="text-slate-500">heap</span>
                <span className="text-white">{st.freeHeap}</span>
              </li>
              <li className="flex justify-between">
                <span className="text-slate-500">PN532</span>
                <span className="text-bubble-accent">
                  {st.pn532 ? `IC${st.pn532.ic} v${st.pn532.fwHi}.${st.pn532.fwLo}` : "n/a"}
                </span>
              </li>
            </ul>
          ) : (
            <p className="mt-4 animate-pulse font-mono text-sm text-bubble-accent/60">Pulling status…</p>
          )}
        </motion.div>

        <motion.div
          initial={{ opacity: 0, y: 12 }}
          animate={{ opacity: 1, y: 0 }}
          transition={{ delay: 0.14 }}
          className="glass p-6"
        >
          <h2 className="font-display text-lg font-normal text-bubble-rose/90 text-glow-rose">Live tag</h2>
          {lastTag ? (
            <div className="mt-4 space-y-4 rounded-xl border border-bubble-mint/25 bg-black/35 p-4 shadow-glow">
              <div>
                <p className="text-[10px] font-mono uppercase tracking-widest text-bubble-mint/50">UID</p>
                <div className="font-mono text-xl font-bold tracking-[0.15em] text-glow-matrix text-bubble-mint md:text-2xl">
                  {uidWithSeparators(lastTag.uid)}
                </div>
                <p className="mt-1 font-mono text-[11px] text-slate-500">
                  raw {lastTag.uid} · {lastTag.uidLen} byte{lastTag.uidLen === 1 ? "" : "s"}
                </p>
              </div>
              <div className="grid gap-3 border-t border-white/5 pt-3 font-mono text-[11px] text-slate-300 sm:grid-cols-2">
                <div>
                  <span className="text-slate-500">ATQA</span>{" "}
                  <span className="text-bubble-accent">
                    0x{(lastTag.atqaHex ?? lastTag.atqa.toString(16).toUpperCase().padStart(4, "0")).slice(-4)}
                  </span>
                  <span className="ml-2 text-slate-500">({lastTag.atqa})</span>
                </div>
                <div>
                  <span className="text-slate-500">SAK</span>{" "}
                  <span className="text-bubble-accent">
                    0x{(lastTag.sakHex ?? lastTag.sak.toString(16).toUpperCase().padStart(2, "0")).slice(-2)}
                  </span>
                  <span className="ml-1 text-slate-400">— {sakLabel(lastTag.sak)}</span>
                </div>
                <div className="sm:col-span-2">
                  <span className="text-slate-500">Guess</span>{" "}
                  <span className="text-bubble-mint">{lastTag.typeGuess ?? typeHintLabel(lastTag.typeHint)}</span>
                  <span className="ml-2 text-slate-600">· hint {lastTag.typeHint}</span>
                </div>
              </div>
              {lastTag.pn532GeneralStatus && lastTag.pn532GeneralStatus.length > 0 && (
                <div className="rounded-lg border border-bubble-accent/20 bg-black/40 p-3">
                  <p className="text-[10px] font-mono uppercase tracking-widest text-bubble-accent/70">
                    PN532 general status
                  </p>
                  <p className="mt-2 break-all font-mono text-[10px] leading-relaxed text-slate-400">
                    {generalStatusHexLine(lastTag.pn532GeneralStatus)}
                  </p>
                  <p className="mt-2 text-[10px] text-slate-600">
                    Raw bytes from the chip right after this inventory (error flags, last command, tag count —
                    see NXP PN532 user manual).
                  </p>
                </div>
              )}
              <ul className="space-y-1 border-t border-white/5 pt-3 text-[11px] leading-relaxed text-slate-500">
                {scanCheatLines(lastTag).map((line, i) => (
                  <li key={i} className="flex gap-2">
                    <span className="text-bubble-mint/40">▸</span>
                    <span>{line}</span>
                  </li>
                ))}
              </ul>
            </div>
          ) : (
            <p className="mt-6 font-mono text-sm text-bubble-mint/40">Listening on the field…</p>
          )}
        </motion.div>
      </div>
    </div>
  );
}
