import { useState, useEffect, useRef, useCallback } from "react";
import { useParams, useNavigate } from "react-router-dom";
import { useAuth } from "../auth/AuthContext";
import api from "../api/client";

const BOARD_TYPE_LABELS = {
  vesper: "Vesper", vesper_plus: "Vesper+", vesper_pro: "Vesper Pro",
  chronos: "Chronos", chronos_pro: "Chronos Pro", agnus_mini: "Agnus Mini", agnus: "Agnus",
};

// hex values mirror index.css --lc-* variables so we can build rgba() strings in JS
const LIFECYCLE = [
  { key: "manufactured",   label: "Manufactured",   icon: "🔩", color: "var(--lc-manufactured-text)",   bg: "var(--lc-manufactured-bg)",   accent: "var(--lc-manufactured-accent)",   accentHex: "#4da8c8", bgHex: "#1a2e3f" },
  { key: "flashed",        label: "Flashed",         icon: "⚡", color: "var(--lc-flashed-text)",         bg: "var(--lc-flashed-bg)",         accent: "var(--lc-flashed-accent)",         accentHex: "#c9a83c", bgHex: "#2e2800" },
  { key: "provisioned",    label: "Provisioned",     icon: "📡", color: "var(--lc-provisioned-text)",     bg: "var(--lc-provisioned-bg)",     accent: "var(--lc-provisioned-accent)",     accentHex: "#c97a28", bgHex: "#2e1a00" },
  { key: "sold",           label: "Sold",            icon: "📦", color: "var(--lc-sold-text)",            bg: "var(--lc-sold-bg)",            accent: "var(--lc-sold-accent)",            accentHex: "#3daa6a", bgHex: "#0e2a1a" },
  { key: "claimed",        label: "Claimed",         icon: "✅", color: "var(--lc-claimed-text)",         bg: "var(--lc-claimed-bg)",         accent: "var(--lc-claimed-accent)",         accentHex: "#22c55e", bgHex: "#0a2416" },
  { key: "decommissioned", label: "Decommissioned",  icon: "🗑", color: "var(--lc-decommissioned-text)",  bg: "var(--lc-decommissioned-bg)",  accent: "var(--lc-decommissioned-accent)",  accentHex: "#ef4444", bgHex: "#2a0a0a" },
];

const STEP_INDEX = Object.fromEntries(LIFECYCLE.map((s, i) => [s.key, i]));
const PROTECTED_STATUSES = ["sold", "claimed"];

function formatHwVersion(v) {
  if (!v) return "—";
  if (/^\d+\.\d+/.test(v)) return `Rev ${v}`;
  const n = parseInt(v, 10);
  if (!isNaN(n)) return `Rev ${n}.0`;
  return `Rev ${v}`;
}

function formatDate(iso) {
  if (!iso) return "—";
  try {
    return new Date(iso).toLocaleString("en-US", {
      year: "numeric", month: "short", day: "numeric",
      hour: "2-digit", minute: "2-digit",
    });
  } catch { return iso; }
}

function toDatetimeLocal(iso) {
  if (!iso) return "";
  try {
    const d = new Date(iso);
    const pad = (n) => String(n).padStart(2, "0");
    return `${d.getFullYear()}-${pad(d.getMonth()+1)}-${pad(d.getDate())}T${pad(d.getHours())}:${pad(d.getMinutes())}`;
  } catch { return ""; }
}

function Field({ label, value, mono = false }) {
  return (
    <div>
      <p className="ui-field-label mb-0.5">{label}</p>
      <p className={`text-sm ${mono ? "font-mono" : ""}`} style={{ color: "var(--text-primary)" }}>
        {value || "—"}
      </p>
    </div>
  );
}

// ─── Shared 3-step assignment modal ───────────────────────────────────────────
// mode: "claimed" (user search) | "sold" (customer search, pre-assigned)

function AssignmentFlowModal({ mode, device, assignedCustomer, existingUsers = [], onComplete, onCancel }) {
  // mode="sold": customer is already assigned (or being assigned), we just confirm + email
  // mode="claimed": pick a user first
  const isClaimed = mode === "claimed";
  const accentColor = isClaimed ? "var(--lc-claimed-accent)" : "var(--lc-sold-accent)";
  const accentBg    = isClaimed ? "var(--lc-claimed-bg)"     : "var(--lc-sold-bg)";
  const icon        = isClaimed ? "✅" : "📦";
  const modeLabel   = isClaimed ? "Set as Claimed" : "Set as Sold";

  // Step 1: search & select
  const [step, setStep] = useState(1);
  const [selectedUser, setSelectedUser] = useState(null);   // for claimed
  const [keepExisting, setKeepExisting] = useState(false);

  // Step 2: email
  const [sendEmail, setSendEmail] = useState(false);
  const [emailAddress, setEmailAddress] = useState("");

  // Step 3: done
  const [completing, setCompleting] = useState(false);
  const [done, setDone] = useState(false);

  // Search state (claimed only)
  const [query, setQuery] = useState("");
  const [results, setResults] = useState([]);
  const [searching, setSearching] = useState(false);
  const inputRef = useRef(null);

  useEffect(() => { if (step === 1) inputRef.current?.focus(); }, [step]);

  const search = useCallback(async (q) => {
    setSearching(true);
    try {
      const data = await api.get(`/users?search=${encodeURIComponent(q)}&limit=20`);
      setResults(data.users || data || []);
    } catch { setResults([]); }
    finally { setSearching(false); }
  }, []);

  useEffect(() => {
    if (!isClaimed) return;
    const t = setTimeout(() => search(query), 300);
    return () => clearTimeout(t);
  }, [query, search, isClaimed]);

  // Prefill email when moving to step 2
  const advanceToEmailStep = (user, keep = false) => {
    setSelectedUser(user);
    setKeepExisting(keep);
    // Pre-fill email from selected entity
    const prefill = isClaimed
      ? (user?.email || "")
      : (assignedCustomer?.email || "");
    setEmailAddress(prefill);
    setStep(2);
  };

  // For sold mode: step 1 is skipped (customer already known), go straight to email
  useEffect(() => {
    if (!isClaimed && step === 1) {
      setStep(2);
    }
  }, [isClaimed, step]);

  // Pre-fill email for sold mode whenever assignedCustomer becomes available
  useEffect(() => {
    if (!isClaimed && !emailAddress) {
      setEmailAddress(assignedCustomer?.email || "");
    }
  }, [isClaimed, assignedCustomer]);

  const handleComplete = async () => {
    setCompleting(true);
    try {
      await onComplete({ user: selectedUser, keepExisting, sendEmail, emailAddress });
      setDone(true);
      setTimeout(() => onCancel(), 1400);
    } catch {
      setCompleting(false);
    }
  };

  // ESC / backdrop close
  useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") onCancel(); };
    document.addEventListener("keydown", onKey);
    return () => document.removeEventListener("keydown", onKey);
  }, [onCancel]);

  return (
    <div
      className="fixed inset-0 z-50 flex items-center justify-center"
      style={{ backgroundColor: "rgba(0,0,0,0.68)" }}
      onClick={(e) => { if (e.target === e.currentTarget) onCancel(); }}
    >
      <div className="rounded-xl border shadow-2xl w-full max-w-md" style={{ backgroundColor: "var(--bg-card)", borderColor: accentColor + "60" }}>

        {/* Header */}
        <div className="flex items-center gap-3 px-5 pt-5 pb-4 border-b" style={{ borderColor: "var(--border-secondary)" }}>
          <div className="w-8 h-8 rounded-lg flex items-center justify-center flex-shrink-0"
            style={{ backgroundColor: accentBg, border: `1px solid ${accentColor}40` }}>
            <span>{icon}</span>
          </div>
          <div className="flex-1">
            <p className="text-xs font-semibold uppercase tracking-wider" style={{ color: accentColor }}>{modeLabel}</p>
            <h2 className="text-sm font-bold" style={{ color: "var(--text-heading)" }}>
              {done ? "Done!" : step === 1 ? (isClaimed ? "Select User" : "Select Customer") : step === 2 ? "Send Email?" : "Complete"}
            </h2>
          </div>
          {/* Step indicator */}
          {!done && (
            <div className="flex items-center gap-1.5 flex-shrink-0">
              {(isClaimed ? [1, 2, 3] : [2, 3]).map((s) => (
                <div key={s} style={{
                  width: 6, height: 6, borderRadius: "50%",
                  backgroundColor: step === s ? accentColor : step > s ? accentColor + "60" : "var(--border-secondary)",
                  transition: "background 0.2s",
                }} />
              ))}
            </div>
          )}
        </div>

        <div className="px-5 py-4">

          {/* ── DONE state ─────────────────────────────────────── */}
          {done && (
            <div className="flex flex-col items-center py-6 gap-3">
              <div style={{
                width: 52, height: 52, borderRadius: "50%",
                backgroundColor: accentBg,
                border: `2px solid ${accentColor}`,
                display: "flex", alignItems: "center", justifyContent: "center",
                fontSize: "1.6rem",
                animation: "lc-pop 0.3s ease",
              }}>✓</div>
              <p className="text-sm font-medium" style={{ color: "var(--text-heading)" }}>
                {isClaimed ? "Device marked as Claimed" : "Device marked as Sold"}
              </p>
              {sendEmail && <p className="text-xs" style={{ color: "var(--text-muted)" }}>Email sent to {emailAddress}</p>}
            </div>
          )}

          {/* ── STEP 1: User search (claimed only) ──────────────── */}
          {!done && step === 1 && isClaimed && (
            <>
              <p className="text-xs mb-3" style={{ color: "var(--text-muted)" }}>
                Search and select the user to assign to this device.
              </p>

              {existingUsers.length > 0 && (
                <div className="mb-3">
                  <p className="text-xs font-medium mb-1.5" style={{ color: "var(--text-muted)" }}>Already assigned</p>
                  {existingUsers.map((u) => (
                    <button key={u.uid} type="button" onClick={() => advanceToEmailStep(u, true)}
                      className="w-full text-left px-3 py-2.5 text-sm rounded-lg border mb-1.5 flex items-center gap-3 cursor-pointer hover:opacity-80 transition-opacity"
                      style={{ backgroundColor: accentBg, borderColor: accentColor + "40", color: "var(--text-primary)" }}>
                      <div className="w-6 h-6 rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"
                        style={{ backgroundColor: accentColor + "30", color: accentColor }}>
                        {(u.display_name || u.email || "U")[0].toUpperCase()}
                      </div>
                      <div className="min-w-0 flex-1">
                        <span className="font-medium block truncate">{u.display_name || u.email || u.uid}</span>
                        {u.email && u.display_name && <span className="text-xs block" style={{ color: "var(--text-muted)" }}>{u.email}</span>}
                      </div>
                      <span className="text-xs flex-shrink-0 px-2 py-0.5 rounded"
                        style={{ backgroundColor: accentColor + "20", color: accentColor, border: `1px solid ${accentColor}40` }}>
                        Keep &amp; Proceed
                      </span>
                    </button>
                  ))}
                  <div className="flex items-center gap-2 my-3">
                    <div className="flex-1 h-px" style={{ backgroundColor: "var(--border-secondary)" }} />
                    <span className="text-xs" style={{ color: "var(--text-muted)" }}>or assign a different user</span>
                    <div className="flex-1 h-px" style={{ backgroundColor: "var(--border-secondary)" }} />
                  </div>
                </div>
              )}

              <div style={{ position: "relative" }} className="mb-2">
                <input ref={inputRef} type="text" value={query}
                  onChange={(e) => setQuery(e.target.value)}
                  placeholder="Search by name or email…"
                  className="w-full px-3 py-2 rounded-md text-sm border"
                  style={{ backgroundColor: "var(--bg-input)", borderColor: "var(--border-input)", color: "var(--text-primary)" }}
                />
                {searching && <span className="absolute right-3 top-1/2 -translate-y-1/2 text-xs" style={{ color: "var(--text-muted)" }}>…</span>}
              </div>
              <div className="rounded-md border overflow-y-auto mb-4" style={{ borderColor: "var(--border-secondary)", maxHeight: 200, minHeight: 44 }}>
                {results.length === 0 ? (
                  <p className="px-3 py-3 text-sm" style={{ color: "var(--text-muted)" }}>
                    {searching ? "Searching…" : query ? "No users found." : "Type to search users…"}
                  </p>
                ) : results.map((u) => (
                  <button key={u.id || u.uid} type="button" onClick={() => advanceToEmailStep(u, false)}
                    className="w-full text-left px-3 py-2.5 text-sm hover:opacity-80 cursor-pointer border-b last:border-b-0 transition-colors"
                    style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-secondary)", color: "var(--text-primary)" }}>
                    <span className="font-medium">{u.display_name || u.name || u.email || u.id}</span>
                    {u.email && <span className="block text-xs" style={{ color: "var(--text-muted)" }}>{u.email}</span>}
                  </button>
                ))}
              </div>
              <div className="flex justify-end">
                <button onClick={onCancel} className="px-4 py-1.5 text-sm rounded-md hover:opacity-80 cursor-pointer"
                  style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)" }}>Cancel</button>
              </div>
            </>
          )}

          {/* ── STEP 2: Send email? ──────────────────────────────── */}
          {!done && step === 2 && (
            <>
              {/* Selected entity summary */}
              {isClaimed && selectedUser && (
                <div className="flex items-center gap-2 px-3 py-2 rounded-lg border mb-4 text-sm"
                  style={{ backgroundColor: accentBg, borderColor: accentColor + "40" }}>
                  <span style={{ color: accentColor }}>✓</span>
                  <span style={{ color: "var(--text-primary)" }}>{selectedUser.display_name || selectedUser.name || selectedUser.email}</span>
                  {!keepExisting && <button type="button" onClick={() => setStep(1)}
                    className="ml-auto text-xs hover:opacity-80 cursor-pointer" style={{ color: "var(--text-muted)" }}>Change</button>}
                </div>
              )}
              {!isClaimed && assignedCustomer && (
                <div className="flex items-center gap-2 px-3 py-2 rounded-lg border mb-4 text-sm"
                  style={{ backgroundColor: accentBg, borderColor: accentColor + "40" }}>
                  <span style={{ color: accentColor }}>✓</span>
                  <span style={{ color: "var(--text-primary)" }}>
                    {[assignedCustomer.name, assignedCustomer.surname].filter(Boolean).join(" ") || "Customer"}
                  </span>
                </div>
              )}

              <p className="text-xs font-semibold uppercase tracking-wider mb-3" style={{ color: "var(--text-muted)" }}>
                Send notification email?
              </p>
              <div className="flex gap-3 mb-4">
                <button type="button" onClick={() => setSendEmail(false)}
                  className="flex-1 py-3 rounded-lg border text-sm font-medium cursor-pointer transition-all"
                  style={{
                    backgroundColor: !sendEmail ? accentBg : "var(--bg-input)",
                    borderColor: !sendEmail ? accentColor : "var(--border-input)",
                    color: !sendEmail ? accentColor : "var(--text-secondary)",
                  }}>
                  ✗ Do Not Send
                </button>
                <button type="button" onClick={() => setSendEmail(true)}
                  className="flex-1 py-3 rounded-lg border text-sm font-medium cursor-pointer transition-all"
                  style={{
                    backgroundColor: sendEmail ? accentBg : "var(--bg-input)",
                    borderColor: sendEmail ? accentColor : "var(--border-input)",
                    color: sendEmail ? accentColor : "var(--text-secondary)",
                  }}>
                  ✉ Send Email
                </button>
              </div>

              {sendEmail && (
                <div className="mb-4">
                  <label className="block text-xs font-medium mb-1.5" style={{ color: "var(--text-muted)" }}>Email address</label>
                  <input type="email" value={emailAddress} onChange={(e) => setEmailAddress(e.target.value)}
                    className="w-full px-3 py-2 rounded-md text-sm border"
                    style={{ backgroundColor: "var(--bg-input)", borderColor: "var(--border-input)", color: "var(--text-primary)" }}
                  />
                </div>
              )}

              <div className="flex gap-3 justify-between">
                {isClaimed ? (
                  <button onClick={() => setStep(1)} className="px-4 py-1.5 text-sm rounded-md hover:opacity-80 cursor-pointer"
                    style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)" }}>← Back</button>
                ) : (
                  <button onClick={onCancel} className="px-4 py-1.5 text-sm rounded-md hover:opacity-80 cursor-pointer"
                    style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)" }}>Cancel</button>
                )}
                <button onClick={handleComplete} disabled={completing}
                  className="px-5 py-1.5 text-sm rounded-md font-semibold hover:opacity-90 cursor-pointer disabled:opacity-50"
                  style={{ backgroundColor: accentColor, color: "#fff" }}>
                  {completing ? "Processing…" : "Complete →"}
                </button>
              </div>
            </>
          )}

        </div>
      </div>
    </div>
  );
}

// Keep CustomerSearchModal for the "Assign to Customer" action (not the lifecycle modal)
// ─── Customer Search Modal ─────────────────────────────────────────────────

// ─── Customer Search Modal ─────────────────────────────────────────────────

function CustomerSearchModal({ onSelect, onCancel }) {
  const [query, setQuery] = useState("");
  const [results, setResults] = useState([]);
  const [searching, setSearching] = useState(false);
  const inputRef = useRef(null);

  useEffect(() => { inputRef.current?.focus(); }, []);

  const search = useCallback(async (q) => {
    setSearching(true);
    try {
      const data = await api.get(`/manufacturing/customers/search?q=${encodeURIComponent(q)}`);
      setResults(data.results || []);
    } catch {
      setResults([]);
    } finally {
      setSearching(false);
    }
  }, []);

  useEffect(() => {
    const t = setTimeout(() => search(query), 250);
    return () => clearTimeout(t);
  }, [query, search]);

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center" style={{ backgroundColor: "rgba(0,0,0,0.6)" }}>
      <div className="rounded-xl border p-6 w-full max-w-md" style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-primary)" }}>
        <h2 className="text-base font-bold mb-4" style={{ color: "var(--text-heading)" }}>Assign to Customer</h2>
        <div style={{ position: "relative" }} className="mb-3">
          <input
            ref={inputRef}
            type="text"
            value={query}
            onChange={(e) => setQuery(e.target.value)}
            placeholder="Search by name, email, phone, org, tags…"
            className="w-full px-3 py-2 rounded-md text-sm border"
            style={{ backgroundColor: "var(--bg-input)", borderColor: "var(--border-input)", color: "var(--text-primary)" }}
          />
          {searching && <span className="absolute right-3 top-1/2 -translate-y-1/2 text-xs" style={{ color: "var(--text-muted)" }}>…</span>}
        </div>
        <div className="rounded-md border overflow-y-auto" style={{ borderColor: "var(--border-secondary)", maxHeight: 260, minHeight: 48 }}>
          {results.length === 0 ? (
            <p className="px-3 py-3 text-sm" style={{ color: "var(--text-muted)" }}>
              {searching ? "Searching…" : query ? "No customers found." : "Type to search customers…"}
            </p>
          ) : results.map((c) => {
            const fullName = [c.name, c.surname].filter(Boolean).join(" ") || c.email || c.id;
            return (
              <button key={c.id} type="button" onClick={() => onSelect(c)}
                className="w-full text-left px-3 py-2.5 text-sm hover:opacity-80 cursor-pointer border-b last:border-b-0 transition-colors"
                style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--border-secondary)", color: "var(--text-primary)" }}>
                <span className="font-semibold block">{fullName}</span>
                {c.organization && <span className="block text-xs" style={{ color: "var(--text-muted)" }}>{c.organization}</span>}
                {c.city && <span className="block text-xs" style={{ color: "var(--text-muted)" }}>{c.city}</span>}
              </button>
            );
          })}
        </div>
        <div className="flex gap-3 justify-end mt-4">
          <button onClick={onCancel} className="px-4 py-1.5 text-sm rounded-md hover:opacity-80 cursor-pointer"
            style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)" }}>Cancel</button>
        </div>
      </div>
    </div>
  );
}

// ─── Delete Device Modal ──────────────────────────────────────────────────────

function DeleteModal({ device, onConfirm, onCancel, deleting }) {
  const isProtected = PROTECTED_STATUSES.includes(device?.mfg_status);
  const [typed, setTyped] = useState("");
  const confirmed = !isProtected || typed === device?.serial_number;

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center" style={{ backgroundColor: "rgba(0,0,0,0.6)" }}>
      <div className="rounded-xl border p-6 w-full max-w-md" style={{ backgroundColor: "var(--bg-card)", borderColor: "var(--danger)" }}>
        <h2 className="text-base font-bold mb-2" style={{ color: "var(--danger-text)" }}>
          {isProtected ? "⚠ Delete Protected Device" : "Delete Device"}
        </h2>
        {isProtected ? (
          <>
            <p className="text-sm mb-3" style={{ color: "var(--text-secondary)" }}>
              This device has status <strong>{device.mfg_status}</strong> and is linked to a customer. Deleting it is irreversible.
            </p>
            <p className="text-sm mb-3" style={{ color: "var(--text-secondary)" }}>To confirm, type the serial number exactly:</p>
            <p className="font-mono text-sm mb-3 px-3 py-2 rounded" style={{ backgroundColor: "var(--bg-primary)", color: "var(--text-primary)" }}>{device.serial_number}</p>
            <input type="text" value={typed} onChange={(e) => setTyped(e.target.value)} onPaste={(e) => e.preventDefault()}
              placeholder="Type serial number here…" autoComplete="off"
              className="w-full px-3 py-2 rounded-md text-sm border mb-4 font-mono"
              style={{ backgroundColor: "var(--bg-input)", borderColor: typed === device.serial_number ? "var(--accent)" : "var(--border-input)", color: "var(--text-primary)" }} />
          </>
        ) : (
          <p className="text-sm mb-4" style={{ color: "var(--text-secondary)" }}>
            Are you sure you want to delete <strong className="font-mono">{device?.serial_number}</strong>? This cannot be undone.
          </p>
        )}
        <div className="flex gap-3 justify-end">
          <button onClick={onCancel} className="px-4 py-1.5 text-sm rounded-md hover:opacity-80 cursor-pointer"
            style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)" }}>Cancel</button>
          <button onClick={onConfirm} disabled={!confirmed || deleting}
            className="px-4 py-1.5 text-sm rounded-md font-medium hover:opacity-90 cursor-pointer disabled:opacity-40"
            style={{ backgroundColor: "var(--danger)", color: "#fff" }}>
            {deleting ? "Deleting…" : "Delete Device"}
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── Lifecycle Entry Edit Modal ────────────────────────────────────────────────

function LifecycleEditModal({ entry, stepMeta, isCurrent, onSave, onDelete, onCancel }) {
  const isNew = !entry;
  const [dateVal, setDateVal] = useState(() => isNew ? toDatetimeLocal(new Date().toISOString()) : toDatetimeLocal(entry?.date));
  const [note, setNote] = useState(entry?.note || "");
  const [saving, setSaving] = useState(false);
  const [deleting, setDeleting] = useState(false);
  const [confirmDelete, setConfirmDelete] = useState(false);

  const handleSave = async () => {
    setSaving(true);
    try {
      const isoDate = dateVal ? new Date(dateVal).toISOString() : new Date().toISOString();
      await onSave(isoDate, note);
    } finally {
      setSaving(false);
    }
  };

  const handleDelete = async () => {
    setDeleting(true);
    try {
      await onDelete();
    } finally {
      setDeleting(false);
      setConfirmDelete(false);
    }
  };

  return (
    <div className="fixed inset-0 z-50 flex items-center justify-center" style={{ backgroundColor: "rgba(0,0,0,0.75)" }}>
      <div className="rounded-2xl border p-6 w-full max-w-sm shadow-2xl" style={{ backgroundColor: "var(--bg-card)", borderColor: stepMeta.accent + "60" }}>
        {/* Header */}
        <div className="flex items-center gap-3 mb-5">
          <div className="w-9 h-9 rounded-xl flex items-center justify-center text-lg flex-shrink-0"
            style={{ backgroundColor: stepMeta.bg, border: `1px solid ${stepMeta.accent}40` }}>
            {stepMeta.icon}
          </div>
          <div>
            <p className="text-xs font-semibold uppercase tracking-wider mb-0.5" style={{ color: stepMeta.color }}>
              {isNew ? "Create Step" : "Edit Step"}
            </p>
            <h3 className="text-sm font-bold" style={{ color: "var(--text-heading)" }}>{stepMeta.label}</h3>
          </div>
        </div>

        {/* Date field */}
        <div className="mb-4">
          <label className="block text-xs font-medium mb-1.5" style={{ color: "var(--text-muted)" }}>Date &amp; Time</label>
          <input
            type="datetime-local"
            value={dateVal}
            onChange={(e) => setDateVal(e.target.value)}
            className="w-full px-3 py-2 rounded-lg text-sm border"
            style={{ backgroundColor: "var(--bg-input)", borderColor: "var(--border-input)", color: "var(--text-primary)" }}
          />
        </div>

        {/* Note field */}
        <div className="mb-5">
          <label className="block text-xs font-medium mb-1.5" style={{ color: "var(--text-muted)" }}>
            Note <span style={{ fontWeight: 400 }}>(optional)</span>
          </label>
          <textarea
            value={note}
            onChange={(e) => setNote(e.target.value)}
            maxLength={150}
            rows={4}
            placeholder="Add a note about this step…"
            className="w-full px-3 py-2 rounded-lg text-sm border resize-vertical"
            style={{ backgroundColor: "var(--bg-input)", borderColor: "var(--border-input)", color: "var(--text-primary)" }}
          />
          <p className="text-xs mt-1 text-right" style={{ color: note.length > 130 ? "var(--warning-text, #f59e0b)" : "var(--text-muted)" }}>
            {note.length}/150
          </p>
        </div>

        {/* Delete confirm */}
        {confirmDelete && (
          <div className="mb-4 rounded-lg p-3 border text-xs" style={{ backgroundColor: "var(--danger-bg)", borderColor: "var(--danger)", color: "var(--danger-text)" }}>
            Delete this step record permanently?
            <div className="flex gap-2 mt-2">
              <button onClick={() => setConfirmDelete(false)} className="px-3 py-1 rounded cursor-pointer hover:opacity-80"
                style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)" }}>Cancel</button>
              <button onClick={handleDelete} disabled={deleting} className="px-3 py-1 rounded cursor-pointer font-medium hover:opacity-90 disabled:opacity-50"
                style={{ backgroundColor: "var(--danger)", color: "#fff" }}>
                {deleting ? "Deleting…" : "Yes, Delete"}
              </button>
            </div>
          </div>
        )}

        <div className="flex gap-2 justify-between">
          {/* Delete button — only for existing entries that are NOT current */}
          {!isNew && !isCurrent && !confirmDelete ? (
            <button onClick={() => setConfirmDelete(true)}
              className="px-3 py-1.5 text-xs rounded-lg cursor-pointer hover:opacity-80"
              style={{ backgroundColor: "var(--danger-bg)", color: "var(--danger-text)", border: "1px solid var(--danger)" }}>
              Delete Step
            </button>
          ) : <div />}

          <div className="flex gap-2">
            <button onClick={onCancel} className="px-4 py-1.5 text-sm rounded-lg hover:opacity-80 cursor-pointer"
              style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)" }}>Cancel</button>
            <button onClick={handleSave} disabled={saving}
              className="px-4 py-1.5 text-sm rounded-lg font-medium hover:opacity-90 cursor-pointer disabled:opacity-50"
              style={{ backgroundColor: stepMeta.accent, color: "#fff" }}>
              {saving ? "Saving…" : isNew ? "Create" : "Save"}
            </button>
          </div>
        </div>
      </div>
    </div>
  );
}

// ─── Lifecycle Ladder ────────────────────────────────────────────────────────

function LifecycleLadder({ device, canEdit, onStatusChange, onEditEntry, statusError }) {
  const currentIndex = STEP_INDEX[device?.mfg_status] ?? 0;
  const history = device?.lifecycle_history || [];
  const [hoveredIndex, setHoveredIndex] = useState(null);

  // Map status_id -> last entry in history
  const historyMap = {};
  history.forEach((entry) => {
    historyMap[entry.status_id] = entry;
  });

  return (
    <div>
      {statusError && (
        <div className="text-xs rounded-lg p-2.5 border mb-4"
          style={{ backgroundColor: "var(--danger-bg)", borderColor: "var(--danger)", color: "var(--danger-text)" }}>
          {statusError}
        </div>
      )}

      <div style={{ display: "flex", flexDirection: "column", gap: 0 }}>
        {LIFECYCLE.map((step, i) => {
          const isCurrent = i === currentIndex;
          const isPast = i < currentIndex;
          const isFuture = i > currentIndex;
          const isLast = i === LIFECYCLE.length - 1;
          const entry = historyMap[step.key];
          const hasData = !!entry;
          const isHovered = hoveredIndex === i;

          return (
            <div key={step.key} style={{ display: "flex", alignItems: "stretch", gap: 0 }}>
              {/* Left rail */}
              <div style={{ display: "flex", flexDirection: "column", alignItems: "center", width: 44, flexShrink: 0 }}>
                {/* Step circle — vertically centred with card via flex */}
                <div
                  style={{
                    marginTop: 3,
                    width: 38,
                    height: 38,
                    borderRadius: "50%",
                    border: `2px solid ${isCurrent ? step.accentHex : isPast ? `${step.accentHex}90` : isHovered && canEdit ? `${step.accentHex}60` : `${step.accentHex}30`}`,
                    backgroundColor: isCurrent ? step.bg : isPast ? step.bg : isHovered && canEdit ? `${step.bgHex}99` : `${step.bgHex}55`,
                    display: "flex",
                    alignItems: "center",
                    justifyContent: "center",
                    fontSize: "1rem",
                    flexShrink: 0,
                    opacity: isFuture && !isHovered ? 0.35 : 1,
                    boxShadow: isCurrent ? `0 0 0 3px ${step.accentHex}40, 0 0 14px ${step.accentHex}30` : "none",
                    position: "relative",
                    transition: "all 0.2s",
                    pointerEvents: "none",
                  }}
                >
                  {isPast && (
                    <svg width="14" height="14" viewBox="0 0 14 14" fill="none"
                      style={{ position: "absolute", bottom: -2, right: -2, background: "var(--bg-card)", borderRadius: "50%" }}>
                      <circle cx="7" cy="7" r="6" fill={step.accent} opacity="0.9"/>
                      <path d="M4.5 7L6.2 8.7L9.5 5.3" stroke="white" strokeWidth="1.4" strokeLinecap="round" strokeLinejoin="round"/>
                    </svg>
                  )}
                  <span style={{ fontSize: isCurrent ? "1rem" : "0.85rem" }}>{step.icon}</span>
                </div>

                {/* Connector line — always visible, colour-coded for past, muted for future */}
                {!isLast && (
                  <div style={{
                    width: 2,
                    flexGrow: 1,
                    minHeight: 8,
                    background: isPast || isCurrent
                      ? `linear-gradient(to bottom, ${step.accentHex}90, ${LIFECYCLE[i+1].accentHex}50)`
                      : `linear-gradient(to bottom, ${step.accentHex}30, ${LIFECYCLE[i+1].accentHex}20)`,
                    margin: "2px 0",
                    borderRadius: 1,
                    transition: "background 0.3s",
                  }} />
                )}
              </div>

              {/* Right clickable card */}
              <div
                role={canEdit ? "button" : undefined}
                tabIndex={canEdit ? 0 : undefined}
                onMouseEnter={() => setHoveredIndex(i)}
                onMouseLeave={() => setHoveredIndex(null)}
                onClick={(e) => {
                  // Don't trigger if clicking the EDIT button (it has its own handler)
                  if (e.target.closest("[data-edit-btn]")) return;
                  if (!canEdit) return;
                  onStatusChange(step.key);
                }}
                onKeyDown={(e) => {
                  if (e.key === "Enter" || e.key === " ") {
                    if (!canEdit) return;
                    onStatusChange(step.key);
                  }
                }}
                style={{
                  flex: 1,
                  marginLeft: 10,
                  marginBottom: isLast ? 0 : 6,
                  padding: "10px 12px",
                  borderRadius: 10,
                  border: `1px solid ${
                    isCurrent
                      ? `${step.accentHex}cc`
                      : isHovered && canEdit
                      ? `${step.accentHex}80`
                      : isPast
                      ? `${step.accentHex}40`
                      : `${step.accentHex}30`
                  }`,
                  backgroundColor: isCurrent
                    ? step.bg
                    : isHovered && canEdit
                    ? `${step.bgHex}cc`
                    : isPast
                    ? `${step.bgHex}66`
                    : `${step.bgHex}55`,
                  opacity: isFuture && !isHovered ? 0.5 : isPast && !isHovered ? 0.6 : 1,
                  transition: "border-color 0.18s, background-color 0.18s, opacity 0.18s",
                  cursor: canEdit ? "pointer" : "default",
                  position: "relative",
                  display: "flex",
                  alignItems: hasData ? "flex-start" : "center",
                  justifyContent: "space-between",
                  gap: 8,
                  minHeight: 44,
                }}
              >
                {/* Content */}
                <div style={{ flex: 1, minWidth: 0 }}>
                  {/* Label row */}
                  <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: hasData ? 3 : 0 }}>
                    <span style={{
                      fontSize: "0.78rem",
                      fontWeight: 700,
                      letterSpacing: "0.05em",
                      textTransform: "uppercase",
                      color: isCurrent ? step.color : isPast ? step.color + "bb" : isHovered ? step.color + "90" : "var(--text-muted)",
                    }}>
                      {step.label}
                    </span>
                    {isCurrent && (
                      <span style={{
                        fontSize: "0.58rem",
                        fontWeight: 700,
                        letterSpacing: "0.1em",
                        textTransform: "uppercase",
                        color: step.color,
                        backgroundColor: step.accent + "22",
                        border: `1px solid ${step.accent}45`,
                        padding: "1px 6px",
                        borderRadius: 4,
                      }}>CURRENT</span>
                    )}
                  </div>

                  {/* Date + set_by */}
                  {hasData && (
                    <p style={{ fontSize: "0.7rem", color: isCurrent ? step.color + "99" : "var(--text-muted)", margin: 0, marginBottom: entry.note ? 2 : 0 }}>
                      {formatDate(entry.date)}
                      {entry.set_by && <span style={{ marginLeft: 6, opacity: 0.65 }}>· {entry.set_by}</span>}
                    </p>
                  )}

                  {/* Note */}
                  {entry?.note && (
                    <p style={{ fontSize: "0.7rem", color: "var(--text-secondary)", margin: 0, marginTop: 1, fontStyle: "italic", whiteSpace: "pre-wrap", wordBreak: "break-word" }}>
                      "{entry.note}"
                    </p>
                  )}
                </div>

                {/* EDIT button — only visible on hover */}
                {canEdit && (
                  <button
                    data-edit-btn
                    type="button"
                    onClick={(e) => {
                      e.stopPropagation();
                      onEditEntry(i, entry || null);
                    }}
                    style={{
                      fontSize: "0.58rem",
                      fontWeight: 700,
                      letterSpacing: "0.1em",
                      textTransform: "uppercase",
                      color: isHovered ? step.color : "transparent",
                      backgroundColor: "transparent",
                      border: `1px solid ${isHovered ? step.accent + "55" : "transparent"}`,
                      borderRadius: 5,
                      padding: "2px 8px",
                      cursor: "pointer",
                      flexShrink: 0,
                      alignSelf: "flex-start",
                      transition: "all 0.15s",
                      pointerEvents: isHovered ? "auto" : "none",
                    }}
                    onMouseEnter={(e) => {
                      e.currentTarget.style.backgroundColor = step.bg;
                      e.currentTarget.style.borderColor = step.accent + "80";
                    }}
                    onMouseLeave={(e) => {
                      e.currentTarget.style.backgroundColor = "transparent";
                    }}
                  >
                    EDIT
                  </button>
                )}
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ─── Main Component ───────────────────────────────────────────────────────────

export default function DeviceInventoryDetail() {
  const { sn } = useParams();
  const navigate = useNavigate();
  const { hasPermission } = useAuth();
  const canEdit   = hasPermission("manufacturing", "edit");
  const canDelete = hasPermission("manufacturing", "delete");

  const [device, setDevice] = useState(null);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState("");

  const [statusSaving, setStatusSaving] = useState(false);
  const [statusError, setStatusError] = useState("");

  const [nvsDownloading, setNvsDownloading] = useState(false);

  const [assignedCustomer, setAssignedCustomer] = useState(null);
  const [assignSaving, setAssignSaving] = useState(false);
  const [assignError, setAssignError] = useState("");
  const [showCustomerModal, setShowCustomerModal] = useState(false);

  const [userSaving, setUserSaving] = useState(false);

  const [showDeleteModal, setShowDeleteModal] = useState(false);
  const [deleting, setDeleting] = useState(false);

  // Unified assignment flow modal
  const [assignFlowMode, setAssignFlowMode] = useState(null); // null | "sold" | "claimed"

  // Resolved user info for the assigned users section
  const [resolvedUsers, setResolvedUsers] = useState([]); // [{uid, display_name, email}]

  // Lifecycle edit modal: { stepIndex, entry|null }
  const [editModalData, setEditModalData] = useState(null);

  const loadDevice = async () => {
    setLoading(true);
    setError("");
    try {
      let data = await api.get(`/manufacturing/devices/${sn}`);

      // Auto-upgrade to "claimed" if user_list has entries but status is not yet claimed
      console.log("[auto-claimed] check:", { status: data.mfg_status, user_list: data.user_list });
      if (
        data.user_list?.length > 0 &&
        data.mfg_status !== "claimed" &&
        data.mfg_status !== "decommissioned"
      ) {
        try {
          data = await api.request(`/manufacturing/devices/${sn}/status`, {
            method: "PATCH",
            body: JSON.stringify({
              status: "claimed",
              force_claimed: true,
              note: "Auto-updated to Claimed: a user was found in user_list",
            }),
          });
        } catch (upgradeErr) {
          // Non-fatal — still show the device even if auto-upgrade fails
          console.warn("[auto-claimed] upgrade failed:", upgradeErr?.message || upgradeErr);
        }
      }

      setDevice(data);
      if (data.customer_id) fetchCustomerDetails(data.customer_id);
      if (data.user_list?.length) fetchResolvedUsers(data.user_list);
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
    }
  };

  const fetchCustomerDetails = async (customerId) => {
    try {
      const data = await api.get(`/manufacturing/customers/${customerId}`);
      setAssignedCustomer(data || null);
    } catch {
      setAssignedCustomer(null);
    }
  };

  const fetchResolvedUsers = async (uidList) => {
    const results = await Promise.all(
      uidList.map(async (uid) => {
        try {
          const u = await api.get(`/users/${uid}`);
          return { uid, display_name: u.display_name || "", email: u.email || "" };
        } catch {
          return { uid, display_name: "", email: "" };
        }
      })
    );
    setResolvedUsers(results);
  };

  useEffect(() => { loadDevice(); }, [sn]);

  // ── Status change ──────────────────────────────────────────────────────────
  const handleStatusChange = async (newStatus) => {
    if (newStatus === device?.mfg_status) return;

    if (newStatus === "claimed") {
      setAssignFlowMode("claimed");
      return;
    }
    if (newStatus === "sold" && !device?.customer_id) {
      // No customer yet — open customer search first, then sold flow
      setShowCustomerModal(true);
      return;
    }
    if (newStatus === "sold" && device?.customer_id) {
      setAssignFlowMode("sold");
      return;
    }
    setStatusError("");
    setStatusSaving(true);
    try {
      const updated = await api.request(`/manufacturing/devices/${sn}/status`, {
        method: "PATCH",
        body: JSON.stringify({ status: newStatus }),
      });
      setDevice(updated);
    } catch (err) {
      setStatusError(err.message);
    } finally {
      setStatusSaving(false);
    }
  };

  // ── Unified assignment flow completion ─────────────────────────────────────
  const handleAssignFlowComplete = async ({ user, keepExisting, sendEmail }) => {
    setStatusError("");
    if (assignFlowMode === "claimed") {
      setUserSaving(true);
      try {
        if (!keepExisting) {
          await api.request(`/devices/${device.id}/user-list`, {
            method: "POST",
            body: JSON.stringify({ user_id: user.id || user.uid }),
          });
        }
        const updated = await api.request(`/manufacturing/devices/${sn}/status`, {
          method: "PATCH",
          body: JSON.stringify({ status: "claimed", force_claimed: true }),
        });
        setDevice(updated);
        if (updated.user_list?.length) fetchResolvedUsers(updated.user_list);
        if (sendEmail) {
          try {
            await api.request(`/manufacturing/devices/${sn}/email/assigned`, { method: "POST" });
          } catch (emailErr) {
            setStatusError(`Status updated, but email failed: ${emailErr.message}`);
          }
        }
      } catch (err) {
        setStatusError(err.message);
        throw err; // so modal stays open on error
      } finally {
        setUserSaving(false);
        setAssignFlowMode(null);
      }
    } else {
      // sold
      setStatusSaving(true);
      try {
        const updated = await api.request(`/manufacturing/devices/${sn}/status`, {
          method: "PATCH",
          body: JSON.stringify({ status: "sold" }),
        });
        setDevice(updated);
        if (sendEmail) {
          try {
            await api.request(`/manufacturing/devices/${sn}/email/manufactured`, { method: "POST" });
          } catch (emailErr) {
            setStatusError(`Status updated, but email failed: ${emailErr.message}`);
          }
        }
      } catch (err) {
        setStatusError(err.message);
        throw err;
      } finally {
        setStatusSaving(false);
        setAssignFlowMode(null);
      }
    }
  };

  // ── Customer assign (from "Assign to Customer" section) ───────────────────
  const handleSelectCustomer = async (customer) => {
    setShowCustomerModal(false);
    setAssignError("");
    setAssignSaving(true);
    try {
      const updated = await api.request(`/manufacturing/devices/${sn}/assign`, {
        method: "POST",
        body: JSON.stringify({ customer_id: customer.id }),
      });
      setDevice(updated);
      setAssignedCustomer(customer);
      // After assigning customer, open the sold flow modal
      setAssignFlowMode("sold");
    } catch (err) {
      setAssignError(err.message);
    } finally {
      setAssignSaving(false);
    }
  };

  // ── NVS download ───────────────────────────────────────────────────────────
  const downloadNvs = async () => {
    setNvsDownloading(true);
    try {
      const token = localStorage.getItem("access_token");
      const response = await fetch(`/api/manufacturing/devices/${sn}/nvs.bin`, {
        headers: { Authorization: `Bearer ${token}` },
      });
      if (!response.ok) {
        const err = await response.json().catch(() => ({}));
        throw new Error(err.detail || "Download failed");
      }
      const blob = await response.blob();
      const url = URL.createObjectURL(blob);
      const a = document.createElement("a");
      a.href = url;
      a.download = `${sn}_nvs.bin`;
      a.click();
      URL.revokeObjectURL(url);
    } catch (err) {
      setError(err.message);
    } finally {
      setNvsDownloading(false);
    }
  };

  // ── Device delete ──────────────────────────────────────────────────────────
  const handleDelete = async () => {
    setDeleting(true);
    try {
      const isProtected = PROTECTED_STATUSES.includes(device?.mfg_status);
      const url = `/manufacturing/devices/${sn}${isProtected ? "?force=true" : ""}`;
      await api.request(url, { method: "DELETE" });
      navigate("/manufacturing");
    } catch (err) {
      setError(err.message);
      setShowDeleteModal(false);
    } finally {
      setDeleting(false);
    }
  };

  // ── Lifecycle edit helpers ─────────────────────────────────────────────────
  // Build step_key -> last array index in lifecycle_history
  const history = device?.lifecycle_history || [];
  const historyIndexMap = {};
  history.forEach((entry, idx) => { historyIndexMap[entry.status_id] = idx; });

  const handleEditEntryByStep = (stepIndex, entry) => {
    setEditModalData({ stepIndex, entry });
  };

  const handleSaveLifecycle = async (stepIndex, date, note) => {
    const stepKey = LIFECYCLE[stepIndex]?.key;
    const arrayIndex = historyIndexMap[stepKey];

    if (arrayIndex === undefined) {
      // No existing entry → create on the fly
      const updated = await api.request(`/manufacturing/devices/${sn}/lifecycle`, {
        method: "POST",
        body: JSON.stringify({ status_id: stepKey, date, note }),
      });
      setDevice(updated);
    } else {
      // Edit existing
      const updated = await api.request(`/manufacturing/devices/${sn}/lifecycle`, {
        method: "PATCH",
        body: JSON.stringify({ index: arrayIndex, date, note }),
      });
      setDevice(updated);
    }
    setEditModalData(null);
  };

  const handleDeleteLifecycleStep = async (stepIndex) => {
    const stepKey = LIFECYCLE[stepIndex]?.key;
    const arrayIndex = historyIndexMap[stepKey];
    if (arrayIndex === undefined) { setEditModalData(null); return; }
    const updated = await api.request(`/manufacturing/devices/${sn}/lifecycle/${arrayIndex}`, {
      method: "DELETE",
    });
    setDevice(updated);
    setEditModalData(null);
  };

  // ── Early returns ──────────────────────────────────────────────────────────
  if (loading) {
    return (
      <div className="flex items-center justify-center py-20">
        <p className="text-sm" style={{ color: "var(--text-muted)" }}>Loading…</p>
      </div>
    );
  }

  if (error && !device) {
    return (
      <div className="text-sm rounded-md p-4 border"
        style={{ backgroundColor: "var(--danger-bg)", borderColor: "var(--danger)", color: "var(--danger-text)" }}>
        {error}
      </div>
    );
  }

  const currentStepKey = device?.mfg_status;
  const editStepMeta = editModalData ? LIFECYCLE[editModalData.stepIndex] : null;
  const editIsCurrent = editModalData ? LIFECYCLE[editModalData.stepIndex]?.key === currentStepKey : false;
  const userList = device?.user_list || [];

  return (
    <div style={{ width: "100%" }}>
      {/* Title row */}
      <div className="flex items-start justify-between mb-6">
        <div>
          <h1 className="text-2xl font-bold font-mono" style={{ color: "var(--text-heading)" }}>
            {device?.serial_number}
          </h1>
          {device?.device_name && (
            <p className="text-sm mt-0.5" style={{ color: "var(--text-muted)" }}>{device.device_name}</p>
          )}
        </div>
        {canDelete && (
          <button
            onClick={() => setShowDeleteModal(true)}
            className="flex items-center gap-1.5 px-3 py-1.5 text-xs rounded-md font-medium hover:opacity-80 cursor-pointer transition-opacity"
            style={{ backgroundColor: "var(--danger-bg)", color: "var(--danger-text)", border: "1px solid var(--danger)" }}
          >
            <svg className="w-3.5 h-3.5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
              <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M19 7l-.867 12.142A2 2 0 0116.138 21H7.862a2 2 0 01-1.995-1.858L5 7m5 4v6m4-6v6m1-10V4a1 1 0 00-1-1h-4a1 1 0 00-1 1v3M4 7h16" />
            </svg>
            Delete Device
          </button>
        )}
      </div>

      {error && (
        <div className="text-sm rounded-md p-3 mb-4 border"
          style={{ backgroundColor: "var(--danger-bg)", borderColor: "var(--danger)", color: "var(--danger-text)" }}>
          {error}
        </div>
      )}

      {/* 2-column 50/50 grid */}
      <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 20, alignItems: "start", width: "100%" }}>

        {/* ── LEFT COLUMN ──────────────────────────────────────────────────── */}
        <div style={{ display: "flex", flexDirection: "column", gap: 16 }}>

          {/* Device Identity */}
          <div className="ui-section-card">
            <div className="ui-section-card__title-row">
              <h2 className="ui-section-card__title">Device Identity</h2>
            </div>
            <div className="grid grid-cols-2 gap-4">
              <Field label="Serial Number" value={device?.serial_number} mono />
              <Field label="Batch ID" value={device?.mfg_batch_id} mono />
              <Field label="Hardware Family" value={BOARD_TYPE_LABELS[device?.hw_type] || device?.hw_type} />
              <Field label="HW Version" value={formatHwVersion(device?.hw_version)} />
              <Field label="Created At" value={formatDate(device?.created_at)} />
              {device?.device_name && <Field label="Device Name" value={device.device_name} />}
              <div>
                <p className="ui-field-label mb-0.5">Document ID</p>
                <p className="text-sm font-mono" style={{ color: "var(--text-more-muted)" }}>
                  {device?.id || "—"}
                </p>
              </div>
            </div>
          </div>

          {/* Assign to Customer */}
          {canEdit && (
            <div className="ui-section-card">
              <div className="ui-section-card__title-row">
                <h2 className="ui-section-card__title">Assign to Customer</h2>
              </div>

              {assignError && (
                <div className="text-xs rounded p-2 border mb-3"
                  style={{ backgroundColor: "var(--danger-bg)", borderColor: "var(--danger)", color: "var(--danger-text)" }}>
                  {assignError}
                </div>
              )}

              {device?.customer_id ? (
                <div
                  role="button"
                  tabIndex={0}
                  onClick={(e) => { if (!e.target.closest("[data-reassign-btn]")) navigate(`/crm/customers/${device.customer_id}`); }}
                  onKeyDown={(e) => { if ((e.key === "Enter" || e.key === " ") && !e.target.closest("[data-reassign-btn]")) navigate(`/crm/customers/${device.customer_id}`); }}
                  className="flex items-center gap-3 px-3 py-2 rounded-md border transition-colors"
                  style={{ backgroundColor: "var(--bg-primary)", borderColor: "var(--border-secondary)", cursor: "pointer" }}
                  onMouseEnter={(e) => e.currentTarget.style.borderColor = "var(--border-primary)"}
                  onMouseLeave={(e) => e.currentTarget.style.borderColor = "var(--border-secondary)"}
                >
                  <div className="w-7 h-7 rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"
                    style={{ backgroundColor: "var(--badge-blue-bg)", color: "var(--badge-blue-text)" }}>
                    {(assignedCustomer?.name || "?")[0].toUpperCase()}
                  </div>
                  <div className="min-w-0 flex-1">
                    <p className="text-sm font-semibold" style={{ color: "var(--text-primary)" }}>
                      {[assignedCustomer?.name, assignedCustomer?.surname].filter(Boolean).join(" ") || "Customer"}
                    </p>
                    {assignedCustomer?.organization && <p className="text-xs" style={{ color: "var(--text-muted)" }}>{assignedCustomer.organization}</p>}
                    {assignedCustomer?.city && <p className="text-xs" style={{ color: "var(--text-muted)" }}>{assignedCustomer.city}</p>}
                  </div>
                  <button
                    data-reassign-btn
                    type="button"
                    onClick={(e) => { e.stopPropagation(); setShowCustomerModal(true); }}
                    disabled={assignSaving}
                    className="px-3 py-1.5 text-xs rounded-md cursor-pointer hover:opacity-80 disabled:opacity-50 flex-shrink-0"
                    style={{ backgroundColor: "var(--bg-card-hover)", color: "var(--text-secondary)", border: "1px solid var(--border-primary)" }}>
                    Reassign
                  </button>
                </div>
              ) : (
                <div>
                  <p className="text-sm mb-3" style={{ color: "var(--text-muted)" }}>
                    No customer assigned. Assigning a customer will set the device status to <em>Sold</em>.
                  </p>
                  <button type="button" onClick={() => setShowCustomerModal(true)} disabled={assignSaving}
                    className="flex items-center gap-2 px-4 py-2 text-sm rounded-md hover:opacity-90 transition-opacity cursor-pointer disabled:opacity-50"
                    style={{ backgroundColor: "var(--btn-primary)", color: "var(--text-white)" }}>
                    {assignSaving ? "Assigning…" : "+ Assign to Customer"}
                  </button>
                </div>
              )}
            </div>
          )}

          {/* Assigned Users */}
          <div className="ui-section-card">
            <div className="ui-section-card__title-row">
              <h2 className="ui-section-card__title">Assigned Users</h2>
            </div>
            {userList.length === 0 ? (
              <p className="text-sm" style={{ color: "var(--text-muted)" }}>
                No users assigned to this device.
              </p>
            ) : (
              <div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
                {userList.map((uid) => {
                  const resolved = resolvedUsers.find((u) => u.uid === uid);
                  const displayName = resolved?.display_name || "";
                  const email = resolved?.email || "";
                  const initials = (displayName || email || uid)[0]?.toUpperCase() || "U";
                  return (
                    <div key={uid}
                      role="button"
                      tabIndex={0}
                      onClick={() => navigate(`/users/${uid}`)}
                      onKeyDown={(e) => { if (e.key === "Enter" || e.key === " ") navigate(`/users/${uid}`); }}
                      className="flex items-center gap-3 px-3 py-2 rounded-md border transition-colors"
                      style={{ backgroundColor: "var(--bg-primary)", borderColor: "var(--border-secondary)", cursor: "pointer" }}
                      onMouseEnter={(e) => e.currentTarget.style.borderColor = "var(--border-primary)"}
                      onMouseLeave={(e) => e.currentTarget.style.borderColor = "var(--border-secondary)"}
                    >
                      <div className="w-7 h-7 rounded-full flex items-center justify-center text-xs font-bold flex-shrink-0"
                        style={{ backgroundColor: "var(--lc-claimed-bg)", color: "var(--lc-claimed-text)" }}>
                        {initials}
                      </div>
                      <div className="min-w-0">
                        {displayName
                          ? <p className="text-sm font-medium" style={{ color: "var(--text-primary)" }}>{displayName}</p>
                          : <p className="text-sm font-mono" style={{ color: "var(--text-muted)" }}>{uid}</p>
                        }
                        {email && <p className="text-xs" style={{ color: "var(--text-muted)" }}>{email}</p>}
                      </div>
                      <svg className="w-3.5 h-3.5 flex-shrink-0 ml-auto" fill="none" stroke="currentColor" viewBox="0 0 24 24" style={{ color: "var(--text-muted)" }}>
                        <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
                      </svg>
                    </div>
                  );
                })}
              </div>
            )}
          </div>

        </div>

        {/* ── RIGHT COLUMN: Lifecycle ───────────────────────────────────────── */}
        <div style={{ display: "flex", flexDirection: "column", gap: 20 }}>
        <div className="ui-section-card">
          <div className="ui-section-card__title-row">
            <h2 className="ui-section-card__title">Product Lifecycle</h2>
            {(statusSaving || userSaving) && (
              <span className="text-xs" style={{ color: "var(--text-muted)" }}>Saving…</span>
            )}
          </div>
          <LifecycleLadder
            device={device}
            canEdit={canEdit}
            onStatusChange={handleStatusChange}
            onEditEntry={handleEditEntryByStep}
            statusError={statusError}
          />
        </div>

          {/* NVS Binary */}
          <div className="ui-section-card">
            <div className="ui-section-card__title-row">
              <h2 className="ui-section-card__title">NVS Binary</h2>
            </div>
            <button
              onClick={downloadNvs}
              disabled={nvsDownloading}
              className="px-4 py-2 text-sm rounded-md hover:opacity-90 transition-opacity cursor-pointer disabled:opacity-50 flex items-center gap-2"
              style={{ backgroundColor: "var(--badge-blue-bg)", color: "var(--badge-blue-text)" }}
            >
              <svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" />
              </svg>
              {nvsDownloading ? "Generating…" : "Download NVS Binary"}
            </button>
            <p className="text-xs mt-2" style={{ color: "var(--text-muted)" }}>
              Encodes serial_number, hw_family, hw_version. Flash at 0x9000.
            </p>
          </div>
        </div>

      </div>

      {/* ── Modals ──────────────────────────────────────────────────────────── */}
      {showCustomerModal && (
        <CustomerSearchModal onSelect={handleSelectCustomer} onCancel={() => setShowCustomerModal(false)} />
      )}
      {assignFlowMode && (
        <AssignmentFlowModal
          mode={assignFlowMode}
          device={device}
          assignedCustomer={assignedCustomer}
          existingUsers={resolvedUsers}
          onComplete={handleAssignFlowComplete}
          onCancel={() => setAssignFlowMode(null)}
        />
      )}
      {showDeleteModal && (
        <DeleteModal device={device} onConfirm={handleDelete} onCancel={() => setShowDeleteModal(false)} deleting={deleting} />
      )}
      {editModalData && editStepMeta && (
        <LifecycleEditModal
          entry={editModalData.entry}
          stepMeta={editStepMeta}
          isCurrent={editIsCurrent}
          onSave={(date, note) => handleSaveLifecycle(editModalData.stepIndex, date, note)}
          onDelete={() => handleDeleteLifecycleStep(editModalData.stepIndex)}
          onCancel={() => setEditModalData(null)}
        />
      )}
    </div>
  );
}
