/* NutriDMS, Integration system (dashboard + canvas-linking flow) */

// ───── Service catalog ─────
const INTEGRATION_CATEGORIES = {
  "Productivity":    { color: "#6938EF", bg: "#F4F3FF" },
  "Calendar":        { color: "#0BA5EC", bg: "#F0F9FF" },
  "Data & Reporting":{ color: "#15B79E", bg: "#F0FDF9" },
  "Communication":   { color: "#DD2590", bg: "#FDF2FA" },
  "Notification":    { color: "#DC6803", bg: "#FFFAEB" },
  "Task Management": { color: "#3b7c0f", bg: "#F3FEE7" },
  "Security":        { color: "#1D2939", bg: "#F2F4F7" },
  "Analytics":       { color: "#2A54E5", bg: "#EFF4FF" },
  "Storage":         { color: "#0E9384", bg: "#F0FDF9" },
};

const SERVICE_CATALOG = [
  // Security
  { id: "okta",      name: "Okta",            cat: "Security",         brand: "okta",            color: "#000000", desc: "Single sign-on, MFA, and identity governance." },
  { id: "auth0",     name: "Auth0 Guardian",  cat: "Security",         brand: "auth0",           color: "#EB5424", desc: "Adaptive MFA with push notifications." },
  // Notification
  { id: "gmail",     name: "Gmail",           cat: "Notification",     brand: "gmail",           color: "#EA4335", desc: "Send transactional and review-update emails." },
  { id: "twilio",    name: "Twilio",          cat: "Notification",     brand: "twilio",          color: "#F22F46", desc: "SMS notifications for SLA breaches and approvals." },
  { id: "sendgrid",  name: "SendGrid",        cat: "Notification",     brand: "sendgrid",        color: "#1A82E2", desc: "High-volume transactional email delivery." },
  // Calendar / Productivity
  { id: "gcal",      name: "Google Calendar", cat: "Calendar",         brand: "googlecalendar",  color: "#4285F4", desc: "Schedule recipe reviews and publishing dates." },
  { id: "outlook",   name: "Outlook Calendar",cat: "Calendar",         brand: "microsoftoutlook",color: "#0078D4", desc: "Schedule across Microsoft 365 tenants." },
  // Communication
  { id: "slack",     name: "Slack",           cat: "Communication",    brand: "slack",           color: "#4A154B", desc: "Post review notifications into team channels." },
  { id: "teams",     name: "Microsoft Teams", cat: "Communication",    brand: "microsoftteams",  color: "#6264A7", desc: "Native chat & meeting links in MS Teams." },
  { id: "whatsapp",  name: "WhatsApp",        cat: "Communication",    brand: "whatsapp",        color: "#25D366", desc: "Notify contributors via WhatsApp Business." },
  // Task management
  { id: "clickup",   name: "ClickUp",         cat: "Task Management",  brand: "clickup",         color: "#7B68EE", desc: "Auto-create tasks when recipes need QA review." },
  { id: "asana",     name: "Asana",           cat: "Task Management",  brand: "asana",           color: "#F06A6A", desc: "Create assignments from submitted recipes." },
  { id: "trello",    name: "Trello",          cat: "Task Management",  brand: "trello",          color: "#0079BF", desc: "Card-based editorial pipeline tracking." },
  // Data & Reporting
  { id: "gsheet",    name: "Google Sheets",   cat: "Data & Reporting", brand: "googlesheets",    color: "#0F9D58", desc: "Mirror published recipes to a live spreadsheet." },
  { id: "excel",     name: "Microsoft Excel", cat: "Data & Reporting", brand: "microsoftexcel",  color: "#217346", desc: "Export recipe nutrition data to Excel." },
  // Analytics
  { id: "mixpanel",  name: "Mixpanel",        cat: "Analytics",        brand: "mixpanel",        color: "#7856FF", desc: "Track which recipes drive the most engagement." },
  { id: "ga",        name: "Google Analytics",cat: "Analytics",        brand: "googleanalytics", color: "#E37400", desc: "Public-site engagement tracking." },
  // Storage
  { id: "s3",        name: "Amazon S3",       cat: "Storage",          brand: "amazons3",        color: "#FF9900", desc: "Cover image and gallery storage." },
];

const AUTH_TYPES = { okta: "OAuth", auth0: "OAuth", gmail: "OAuth", twilio: "API key", sendgrid: "API key", gcal: "OAuth", outlook: "OAuth", slack: "OAuth", teams: "OAuth", whatsapp: "API key", clickup: "API key", asana: "OAuth", trello: "OAuth", gsheet: "OAuth", excel: "OAuth", mixpanel: "API key", ga: "OAuth", s3: "AWS key" };

// Initial state, 7 connected (matches "Connected 7" in design), 2 error, 5 disabled
const INITIAL_INTEGRATIONS = [
  { id: "clickup",  status: "connected", enabled: true,  lastSync: "1h 5m ago",  account: "sarah.chen@nutridms.io",  role: "Administrator" },
  { id: "slack",    status: "connected", enabled: true,  lastSync: "8m ago",     account: "#nutri-content",          role: "Administrator" },
  { id: "asana",    status: "connected", enabled: true,  lastSync: "32m ago",    account: "editorial@nutridms.asana",role: "Editorial Manager" },
  { id: "gmail",    status: "connected", enabled: true,  lastSync: "2h ago",     account: "noreply@nutridms.io",     role: "Administrator" },
  { id: "gcal",     status: "connected", enabled: true,  lastSync: "12m ago",    account: "publishing@nutridms.io",  role: "Editorial Manager" },
  { id: "gsheet",   status: "connected", enabled: true,  lastSync: "1d ago",     account: "data@nutridms.io",        role: "Administrator" },
  { id: "s3",       status: "connected", enabled: true,  lastSync: "3m ago",     account: "ap-southeast-2",          role: "Administrator" },
  { id: "twilio",   status: "error",     enabled: true,  lastSync: "Failed 2h ago", account: "+1-555-0123",          role: "Compliance Officer", error: "Invalid API key" },
  { id: "okta",     status: "error",     enabled: true,  lastSync: "Failed 6h ago", account: "nutridms.okta.com",    role: "Administrator", error: "Token expired" },
  { id: "trello",   status: "disabled",  enabled: false, lastSync: "Disabled",    account: "nutridms-editorial",      role: "Editorial Manager" },
  { id: "teams",    status: "disabled",  enabled: false, lastSync: "Disabled",    account: "tenant.onmicrosoft.com",  role: "Administrator" },
  { id: "whatsapp", status: "disabled",  enabled: false, lastSync: "Disabled",    account: "+1-555-0199",             role: "Compliance Officer" },
  { id: "mixpanel", status: "disabled",  enabled: false, lastSync: "Disabled",    account: "nutridms-prod",           role: "Administrator" },
  { id: "excel",    status: "disabled",  enabled: false, lastSync: "Disabled",    account: "nutridms.sharepoint.com", role: "Administrator" },
];

// People you can attach an integration to (roles dropdown)
const INTEGRATION_PEOPLE = [
  { name: "John Doe",        role: "Administrator",       initials: "JD", color: "#EA670C" },
  { name: "Maria Chen",      role: "Editorial Manager",   initials: "MC", color: "#6938EF" },
  { name: "Amaka Kennedy",   role: "Compliance Officer",  initials: "AK", color: "#175CD3" },
  { name: "Richard Lois",    role: "Dietitian",           initials: "RL", color: "#3b7c0f" },
  { name: "Uyieme Effiong",  role: "Media Contributor",   initials: "UE", color: "#0E9384" },
  { name: "Walter Barry",    role: "Media Contributor",   initials: "WB", color: "#7F56D9" },
  { name: "Joe Harper",      role: "Media Contributor",   initials: "JH", color: "#EA670C" },
  { name: "Tamara Lois",     role: "Media Contributor",   initials: "TL", color: "#9AB3FF" },
];

// ───── Brand Logo ─────
function BrandLogo({ brand, color, size = 32, name }) {
  const url = `https://cdn.simpleicons.org/${brand}/${(color || "000000").replace("#", "")}`;
  const [failed, setFailed] = React.useState(false);
  if (failed) {
    return (
      <div style={{
        width: size, height: size, borderRadius: size * 0.22,
        background: color || "#3b7c0f", color: "#fff",
        display: "grid", placeItems: "center", flexShrink: 0,
        fontWeight: 700, fontSize: size * 0.42, letterSpacing: -0.5,
      }}>
        {(name || brand).charAt(0).toUpperCase()}
      </div>
    );
  }
  return (
    <div style={{
      width: size, height: size, borderRadius: size * 0.22,
      background: "#fff", border: "1px solid var(--gray-200)",
      display: "grid", placeItems: "center", flexShrink: 0,
      padding: size * 0.15, overflow: "hidden",
    }}>
      <img src={url} alt={name || brand} style={{ width: "100%", height: "100%", objectFit: "contain" }} onError={() => setFailed(true)} />
    </div>
  );
}

// ───── Main screen state machine ─────
function IntegrationsScreen() {
  const { toast } = useApp();
  const [integrations, setIntegrations] = React.useState(INITIAL_INTEGRATIONS);
  const [phase, setPhase] = React.useState("dashboard"); // dashboard | add | connecting | success
  const [adding, setAdding] = React.useState(null);      // service being added (catalog entry)
  const [assignTo, setAssignTo] = React.useState(INTEGRATION_PEOPLE[0]);
  const [emptyMode, setEmptyMode] = React.useState(false); // toggle empty state for demo

  // Stats
  const counts = React.useMemo(() => ({
    total:     integrations.length,
    connected: integrations.filter(i => i.status === "connected").length,
    error:     integrations.filter(i => i.status === "error").length,
    disabled:  integrations.filter(i => i.status === "disabled").length,
  }), [integrations]);

  const openAdd = () => { setAdding(null); setPhase("add"); };
  const closeAdd = () => { setPhase("dashboard"); setAdding(null); };

  const submitConnect = () => {
    setPhase("connecting");
    setTimeout(() => {
      setPhase("success");
      // Add to list
      setIntegrations((prev) => {
        const filtered = prev.filter((i) => i.id !== adding.id);
        return [
          { id: adding.id, status: "connected", enabled: true, lastSync: "Just now", account: "johndoe12@softlab.com", role: assignTo.role },
          ...filtered,
        ];
      });
    }, 1600);
  };

  const completeSuccess = () => { setPhase("dashboard"); setAdding(null); };

  const toggleEnabled = (id) => {
    setIntegrations((prev) => prev.map((i) => i.id === id ? {
      ...i,
      enabled: !i.enabled,
      status: !i.enabled ? "connected" : "disabled",
      lastSync: !i.enabled ? "Just now" : "Disabled",
    } : i));
    toast("Integration updated");
  };

  // Add canvas view (full-bleed)
  if (phase === "add" || phase === "connecting" || phase === "success") {
    return (
      <AddIntegrationCanvas
        adding={adding}
        setAdding={setAdding}
        assignTo={assignTo}
        setAssignTo={setAssignTo}
        onClose={closeAdd}
        onSubmit={submitConnect}
        phase={phase}
        onSuccessDone={completeSuccess}
        existingIds={new Set(integrations.filter(i => i.status === "connected").map(i => i.id))}
      />
    );
  }

  return (
    <div className="enterprise-integrations">
      <Crumbs path={[{ label: "Home", onClick: () => {} }, { label: "Integration" }]} />
      <div className="page-head">
        <div>
          <h1 className="page-title">Integration</h1>
          <p className="page-sub">Connect and manage third-party services in NutriDMS.</p>
        </div>
        <div style={{ display: "flex", gap: 10 }}>
          <button className="btn secondary" onClick={() => setEmptyMode((v) => !v)} title="Toggle empty state for demo">
            <Icon name={emptyMode ? "eye" : "eye-off"} size={16} /> {emptyMode ? "Show data" : "Empty preview"}
          </button>
          <button className="btn primary" onClick={openAdd}><Icon name="plus" size={16} /> Add integration</button>
        </div>
      </div>

      {/* Stats */}
      <div className="stats" style={{ gridTemplateColumns: "repeat(4, 1fr)", marginBottom: 22 }}>
        <IntStat label="Total"     value={emptyMode ? 0 : counts.total}     icon="link"           tone="info" />
        <IntStat label="Connected" value={emptyMode ? 0 : counts.connected} icon="check-circle-2" tone="success" />
        <IntStat label="Error"     value={emptyMode ? 0 : counts.error}     icon="alert-octagon"  tone="error" />
        <IntStat label="Disabled"  value={emptyMode ? 0 : counts.disabled}  icon="ban"            tone="muted" />
      </div>

      {emptyMode ? (
        <EmptyState onAdd={openAdd} />
      ) : (
        <IntegrationGrid integrations={integrations} onToggle={toggleEnabled} onAdd={openAdd} />
      )}
    </div>
  );
}

function IntStat({ label, value, icon, tone }) {
  return (
    <div className="stat" style={{ display: "flex", alignItems: "center", gap: 16 }}>
      <div className={`stat-icon ${tone}`} style={{ width: 56, height: 56, borderRadius: 14 }}><Icon name={icon} size={24} /></div>
      <div>
        <div className="muted" style={{ fontSize: 13, fontWeight: 500, marginBottom: 2 }}>{label}</div>
        <div className="stat-value" style={{ fontSize: 32 }}>{value}</div>
      </div>
    </div>
  );
}

// ───── Grid + Filter chips ─────
function IntegrationGrid({ integrations, onToggle, onAdd }) {
  const [filter, setFilter] = React.useState("All");
  const [view, setView] = React.useState("grid");
  const cats = ["All", ...Object.keys(INTEGRATION_CATEGORIES)];
  const filtered = integrations
    .map((i) => ({ ...i, service: SERVICE_CATALOG.find((s) => s.id === i.id) }))
    .filter((i) => i.service && (filter === "All" || i.service.cat === filter));

  // Group by category for grid display
  const grouped = filtered.reduce((acc, i) => {
    const cat = i.service.cat;
    (acc[cat] = acc[cat] || []).push(i);
    return acc;
  }, {});

  return (
    <div>
      <div className="card" style={{ padding: 12, marginBottom: 18, display: "flex", alignItems: "center", gap: 10, flexWrap: "wrap" }}>
        <div style={{ display: "flex", gap: 6, flexWrap: "wrap", flex: 1 }}>
          {cats.map((c) => (
            <button key={c} className={`chip ${filter === c ? "on" : ""}`} onClick={() => setFilter(c)}>{c}</button>
          ))}
        </div>
        <ViewToggle value={view} onChange={setView} />
        <button className="btn secondary sm"><Icon name="sliders-horizontal" size={14} /> Filter</button>
        <button className="btn secondary sm">See all <Icon name="arrow-right" size={14} /></button>
      </div>

      {Object.entries(grouped).map(([cat, items]) => (
        <div key={cat} style={{ marginBottom: 24 }}>
          <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 12 }}>
            <h3 className="section-title" style={{ fontSize: 18, margin: 0 }}>{cat}</h3>
            <span className="pill neutral" style={{ fontSize: 11 }}>{items.length}</span>
          </div>
          {view === "grid" ? (
            <div style={{ display: "grid", gridTemplateColumns: "repeat(auto-fill, minmax(340px, 1fr))", gap: 14 }}>
              {items.map((i) => <IntegrationCard key={i.id} item={i} onToggle={() => onToggle(i.id)} />)}
            </div>
          ) : (
            <div className="card" style={{ overflow: "hidden" }}>
              <table className="table">
                <thead><tr>
                  <th>Integration</th>
                  <th>Status</th>
                  <th>Auth</th>
                  <th>Assigned</th>
                  <th>Last sync</th>
                  <th></th>
                </tr></thead>
                <tbody>
                  {items.map((i) => <IntegrationRow key={i.id} item={i} onToggle={() => onToggle(i.id)} />)}
                </tbody>
              </table>
            </div>
          )}
        </div>
      ))}

      {filtered.length === 0 && (
        <div className="empty">
          <div className="icon"><Icon name="search-x" size={24} /></div>
          <h3>No integrations in this category</h3>
          <p>Add one from the catalog to get started.</p>
          <button className="btn primary" style={{ marginTop: 14 }} onClick={onAdd}><Icon name="plus" size={14} /> Add integration</button>
        </div>
      )}
    </div>
  );
}

function IntegrationCard({ item, onToggle }) {
  const s = item.service;
  const statusPill = item.status === "connected" ? "success" : item.status === "error" ? "error" : "neutral";
  const statusLabel = item.status === "connected" ? "Connected" : item.status === "error" ? "Error" : "Disabled";
  return (
    <div className="card" style={{ padding: 18, transition: "border-color .12s ease, transform .12s ease", cursor: "pointer" }}
      onMouseEnter={(e) => { e.currentTarget.style.borderColor = "var(--green-300)"; e.currentTarget.style.transform = "translateY(-1px)"; }}
      onMouseLeave={(e) => { e.currentTarget.style.borderColor = "var(--gray-200)"; e.currentTarget.style.transform = "none"; }}>
      <div style={{ display: "flex", alignItems: "flex-start", justifyContent: "space-between", gap: 12, marginBottom: 12 }}>
        <div style={{ display: "flex", gap: 12, alignItems: "center", minWidth: 0 }}>
          <BrandLogo brand={s.brand} color={s.color} name={s.name} size={44} />
          <div style={{ minWidth: 0 }}>
            <div style={{ fontWeight: 700, fontSize: 16 }}>{s.name}</div>
            <div className="muted" style={{ fontSize: 12 }}>{s.cat}</div>
          </div>
        </div>
        <span className={`pill ${statusPill}`} style={{ flexShrink: 0 }}>{statusLabel}</span>
      </div>
      <p style={{ margin: 0, fontSize: 13, color: "var(--gray-700)", lineHeight: 1.5, minHeight: 38 }}>{s.desc}</p>

      {item.status === "error" && (
        <div className="alert error" style={{ marginTop: 10, padding: "8px 10px", fontSize: 12 }}>
          <Icon name="alert-triangle" size={14} />
          <div><strong>{item.error}</strong></div>
        </div>
      )}

      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "10px 0", borderTop: "1px solid var(--gray-100)", borderBottom: "1px solid var(--gray-100)", marginTop: 12 }}>
        <span className="muted" style={{ fontSize: 13, fontWeight: 500 }}>Auth Type</span>
        <span className="pill info">{AUTH_TYPES[item.id] || "OAuth"}</span>
      </div>

      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", paddingTop: 12 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 8 }}>
          <Toggle on={item.enabled} onClick={onToggle} />
          <span style={{ fontSize: 13, fontWeight: 600 }}>{item.enabled ? "Enabled" : "Disabled"}</span>
        </div>
        <span className="muted" style={{ fontSize: 12, display: "inline-flex", alignItems: "center", gap: 4 }}>
          <Icon name="clock" size={12} /> Last sync {item.lastSync}
        </span>
      </div>
    </div>
  );
}

function IntegrationRow({ item, onToggle }) {
  const s = item.service;
  const statusPill = item.status === "connected" ? "success" : item.status === "error" ? "error" : "neutral";
  const statusLabel = item.status === "connected" ? "Connected" : item.status === "error" ? "Error" : "Disabled";
  return (
    <tr>
      <td>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <BrandLogo brand={s.brand} color={s.color} name={s.name} size={36} />
          <div>
            <div style={{ fontWeight: 600 }}>{s.name}</div>
            <div className="muted" style={{ fontSize: 12 }}>{s.cat}</div>
          </div>
        </div>
      </td>
      <td><span className={`pill ${statusPill}`}>{statusLabel}</span></td>
      <td><span className="pill info">{AUTH_TYPES[item.id] || "OAuth"}</span></td>
      <td>{item.role}</td>
      <td>{item.lastSync}</td>
      <td><Toggle on={item.enabled} onClick={onToggle} /></td>
    </tr>
  );
}

function Toggle({ on, onClick }) {
  return (
    <button onClick={onClick} aria-pressed={on} style={{
      width: 38, height: 22, borderRadius: 999,
      background: on ? "var(--brand-700)" : "var(--gray-300)",
      position: "relative", transition: "background .15s ease",
    }}>
      <span style={{
        position: "absolute", top: 2, left: on ? 18 : 2,
        width: 18, height: 18, borderRadius: 999, background: "#fff",
        transition: "left .15s ease", boxShadow: "0 1px 2px rgba(0,0,0,.2)",
      }} />
    </button>
  );
}

// ───── Empty State ─────
function EmptyState({ onAdd }) {
  return (
    <div className="card" style={{ padding: 60, textAlign: "center" }}>
      <svg width="160" height="120" viewBox="0 0 160 120" style={{ margin: "0 auto 18px" }}>
        <ellipse cx="80" cy="100" rx="64" ry="8" fill="var(--green-50)" />
        <circle cx="80" cy="50" r="44" fill="var(--green-50)" />
        <g transform="translate(56 38)">
          <rect x="0" y="0" width="48" height="36" rx="8" fill="#fff" stroke="var(--green-700)" strokeWidth="2" />
          <path d="M18 12h12M18 18h12M18 24h8" stroke="var(--green-700)" strokeWidth="2" strokeLinecap="round" />
          <circle cx="9" cy="18" r="3" fill="var(--brand-mark)" />
        </g>
        <path d="M48 70 L24 80" stroke="var(--green-300)" strokeWidth="2" strokeDasharray="3 3" />
        <path d="M112 70 L136 80" stroke="var(--green-300)" strokeWidth="2" strokeDasharray="3 3" />
      </svg>
      <h2 style={{ fontFamily: "var(--serif)", fontSize: 28, margin: "0 0 8px" }}>No update found</h2>
      <p className="muted" style={{ margin: "0 auto 20px", maxWidth: 360 }}>Kindly add and connect an integration to get an updated dashboard.</p>
      <button className="btn primary" onClick={onAdd}><Icon name="plus" size={16} /> Add integration</button>
    </div>
  );
}

// ─────────────── ADD INTEGRATION CANVAS (full-bleed) ───────────────
function AddIntegrationCanvas({ adding, setAdding, assignTo, setAssignTo, onClose, onSubmit, phase, onSuccessDone, existingIds }) {
  const [query, setQuery] = React.useState("");
  const [pickRole, setPickRole] = React.useState(false);

  // Group catalog by category
  const grouped = React.useMemo(() => {
    const q = query.toLowerCase();
    const filtered = q ? SERVICE_CATALOG.filter((s) => s.name.toLowerCase().includes(q) || s.cat.toLowerCase().includes(q)) : SERVICE_CATALOG;
    return filtered.reduce((acc, s) => { (acc[s.cat] = acc[s.cat] || []).push(s); return acc; }, {});
  }, [query]);

  return (
    <div style={{ margin: "-28px -36px -80px", padding: "16px 36px 80px", minHeight: "calc(100vh - 64px)", background: "#fff", position: "relative" }}>
      {/* Header */}
      <div style={{ display: "flex", alignItems: "center", gap: 14, marginBottom: 18 }}>
        <button className="icon-btn" onClick={onClose} title="Close" style={{ background: "var(--gray-100)" }}><Icon name="x" size={18} /></button>
        <div style={{ fontFamily: "var(--serif)", fontSize: 22, color: "var(--brand-700)" }}>NutriDMS</div>
        <div className="crumbs" style={{ margin: 0 }}>
          <Icon name="chevron-right" size={12} className="sep" />
          <button onClick={onClose}>Integration dashboard</button>
          <Icon name="chevron-right" size={12} className="sep" />
          <span className="current">Add integration</span>
        </div>
      </div>

      {/* Layout */}
      <div style={{ display: "grid", gridTemplateColumns: "380px 1fr", gap: 0, minHeight: 700, border: "1px solid var(--gray-200)", borderRadius: 16, overflow: "hidden" }}>
        {/* Left: catalog */}
        <div style={{ background: "#fff", borderRight: "1px solid var(--gray-200)", overflow: "hidden", display: "flex", flexDirection: "column", maxHeight: "calc(100vh - 130px)" }}>
          <div style={{ padding: "20px 20px 14px", borderBottom: "1px solid var(--gray-100)" }}>
            <h2 style={{ fontFamily: "var(--serif)", fontSize: 26, margin: 0 }}>Integration</h2>
            <p className="muted" style={{ margin: "4px 0 14px", fontSize: 13, lineHeight: 1.5 }}>Kindly select a third-party integration you want to connect your NutriDMS account to.</p>
            <div className="search" style={{ width: "100%" }}>
              <Icon name="search" size={16} />
              <input value={query} onChange={(e) => setQuery(e.target.value)} placeholder="Search" />
            </div>
          </div>

          <div style={{ overflowY: "auto", padding: "8px 12px 16px" }}>
            {Object.entries(grouped).map(([cat, services]) => (
              <div key={cat} style={{ marginBottom: 8 }}>
                <div style={{ padding: "10px 10px 6px", fontSize: 13, fontWeight: 600, color: "var(--gray-700)", background: "var(--gray-50)", borderRadius: 8 }}>{cat}</div>
                {services.map((s) => {
                  const isSelected = adding?.id === s.id;
                  const isConnected = existingIds.has(s.id);
                  return (
                    <button key={s.id} onClick={() => !isConnected && setAdding(s)}
                      disabled={isConnected}
                      style={{
                        display: "flex", alignItems: "center", gap: 12,
                        width: "100%", padding: "10px 10px", margin: "4px 0",
                        borderRadius: 10, border: `1px solid ${isSelected ? "var(--green-300)" : "transparent"}`,
                        background: isSelected ? "var(--green-50)" : "transparent",
                        textAlign: "left", cursor: isConnected ? "not-allowed" : "pointer",
                        opacity: isConnected ? 0.5 : 1,
                        transition: "background .1s ease, border-color .1s ease",
                      }}
                      onMouseEnter={(e) => { if (!isSelected && !isConnected) e.currentTarget.style.background = "var(--gray-50)"; }}
                      onMouseLeave={(e) => { if (!isSelected && !isConnected) e.currentTarget.style.background = "transparent"; }}>
                      <BrandLogo brand={s.brand} color={s.color} name={s.name} size={36} />
                      <div style={{ flex: 1, minWidth: 0 }}>
                        <div style={{ fontWeight: 600, fontSize: 14 }}>{s.name}</div>
                        <div className="muted" style={{ fontSize: 11 }}>{s.cat}</div>
                      </div>
                      <div style={{
                        width: 24, height: 24, borderRadius: 999,
                        background: isSelected ? "var(--brand-700)" : isConnected ? "var(--success-50)" : "var(--gray-100)",
                        color: isSelected ? "#fff" : isConnected ? "var(--success-600)" : "var(--gray-600)",
                        display: "grid", placeItems: "center",
                      }}>
                        <Icon name={isSelected ? "minus" : isConnected ? "check" : "plus"} size={14} stroke={2.4} />
                      </div>
                    </button>
                  );
                })}
              </div>
            ))}
          </div>
        </div>

        {/* Right: canvas */}
        <div style={{
          background: "#FAFCFB",
          backgroundImage: "radial-gradient(circle, #D5D7DA 1.2px, transparent 1.2px)",
          backgroundSize: "16px 16px",
          position: "relative", padding: 32, overflow: "auto",
        }}>
          {/* User node */}
          <div style={{ position: "absolute", left: 80, top: 60 }}>
            <RoleNode person={assignTo} onChange={() => setPickRole(true)} />
            {pickRole && (
              <RolePicker
                value={assignTo}
                onClose={() => setPickRole(false)}
                onPick={(p) => { setAssignTo(p); setPickRole(false); }}
              />
            )}
          </div>

          {/* Connector line */}
          {adding && (
            <svg style={{ position: "absolute", left: 0, top: 0, width: "100%", height: "100%", pointerEvents: "none" }}>
              <defs>
                <marker id="arrow-int" markerWidth="10" markerHeight="10" refX="6" refY="3" orient="auto">
                  <polygon points="0 0, 6 3, 0 6" fill="var(--green-700)" />
                </marker>
              </defs>
              <path d="M 250 85 L 360 85 L 360 220" stroke="var(--green-700)" strokeWidth="1.5" strokeDasharray="5 4" fill="none" markerEnd="url(#arrow-int)" />
            </svg>
          )}

          {/* Integration node */}
          {adding && (
            <div style={{ position: "absolute", left: 180, top: 230, width: 360 }}>
              <ConnectionCard service={adding} onSubmit={onSubmit} phase={phase} />
            </div>
          )}

          {!adding && (
            <div style={{ position: "absolute", left: "50%", top: "50%", transform: "translate(-50%, -50%)", textAlign: "center", color: "var(--gray-500)" }}>
              <div style={{ width: 56, height: 56, borderRadius: 14, background: "#fff", border: "1px solid var(--gray-200)", display: "grid", placeItems: "center", margin: "0 auto 12px" }}>
                <Icon name="mouse-pointer-click" size={22} />
              </div>
              <div style={{ fontWeight: 600, color: "var(--text-primary)" }}>Pick a service from the left</div>
              <p style={{ fontSize: 13, marginTop: 4, maxWidth: 280 }}>It'll appear on the canvas, linked to the selected role. Fill in credentials to connect.</p>
            </div>
          )}
        </div>
      </div>

      {/* Connecting overlay */}
      {phase === "connecting" && <ConnectingOverlay adding={adding} />}

      {/* Success modal */}
      {phase === "success" && <SuccessModal onClose={onSuccessDone} />}
    </div>
  );
}

function RoleNode({ person, onChange }) {
  return (
    <div onClick={onChange} style={{
      display: "inline-flex", alignItems: "center", gap: 10,
      padding: "10px 16px 10px 10px", borderRadius: 12,
      background: "#fff", border: "1px solid var(--gray-200)",
      boxShadow: "var(--shadow-card)", cursor: "pointer",
      minWidth: 220,
    }}>
      <div className="avatar" style={{ background: person.color }}>{person.initials}</div>
      <div style={{ flex: 1 }}>
        <div style={{ fontWeight: 700, fontSize: 14 }}>{person.name}</div>
        <div className="muted" style={{ fontSize: 12 }}>{person.role}</div>
      </div>
      <Icon name="chevron-down" size={14} style={{ color: "var(--gray-500)" }} />
    </div>
  );
}

function RolePicker({ value, onClose, onPick }) {
  const [q, setQ] = React.useState("");
  const list = INTEGRATION_PEOPLE.filter((p) => !q || p.name.toLowerCase().includes(q.toLowerCase()) || p.role.toLowerCase().includes(q.toLowerCase()));
  React.useEffect(() => {
    const onDoc = (e) => { if (!e.target.closest(".role-picker")) onClose(); };
    document.addEventListener("mousedown", onDoc);
    return () => document.removeEventListener("mousedown", onDoc);
  }, [onClose]);
  return (
    <div className="role-picker" style={{
      position: "absolute", top: "calc(100% + 8px)", left: 0,
      width: 360, maxHeight: 420, overflow: "hidden",
      background: "#fff", border: "1px solid var(--gray-200)", borderRadius: 14,
      boxShadow: "0 12px 32px rgba(0,0,0,.12)", zIndex: 10,
      display: "flex", flexDirection: "column",
    }}>
      <div style={{ padding: 12, borderBottom: "1px solid var(--gray-100)" }}>
        <div className="search" style={{ width: "100%" }}>
          <Icon name="search" size={16} />
          <input autoFocus value={q} onChange={(e) => setQ(e.target.value)} placeholder="Search by name or role" />
        </div>
      </div>
      <div style={{ overflowY: "auto", padding: 8 }}>
        {list.map((p) => (
          <button key={p.name} onClick={() => onPick(p)} style={{
            display: "flex", alignItems: "center", gap: 12, width: "100%",
            padding: "10px 10px", borderRadius: 8, textAlign: "left",
            background: value.name === p.name ? "var(--green-50)" : "transparent",
            border: value.name === p.name ? "1px solid var(--green-200)" : "1px solid transparent",
            transition: "background .1s ease",
          }} onMouseEnter={(e) => { if (value.name !== p.name) e.currentTarget.style.background = "var(--gray-50)"; }}
             onMouseLeave={(e) => { if (value.name !== p.name) e.currentTarget.style.background = "transparent"; }}>
            <div className="avatar" style={{ background: p.color }}>{p.initials}</div>
            <div style={{ flex: 1 }}>
              <div style={{ fontWeight: 700, fontSize: 14 }}>{p.name}</div>
              <div className="muted" style={{ fontSize: 12 }}>{p.role}</div>
            </div>
            {value.name === p.name && <Icon name="check" size={16} style={{ color: "var(--brand-700)" }} />}
          </button>
        ))}
        {list.length === 0 && <div className="muted" style={{ padding: 18, textAlign: "center", fontSize: 13 }}>No matches</div>}
      </div>
    </div>
  );
}

function ConnectionCard({ service, onSubmit, phase }) {
  const [email, setEmail] = React.useState("johndoe12@softlab.com");
  const [showError, setShowError] = React.useState(false);
  const authType = AUTH_TYPES[service.id] || "OAuth";

  const handleConnect = () => {
    if (!email.includes("@")) { setShowError(true); return; }
    onSubmit();
  };

  return (
    <div className="card pad" style={{ width: "100%", boxShadow: "var(--shadow-card)" }}>
      <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, marginBottom: 14 }}>
        <div style={{ display: "flex", alignItems: "center", gap: 12 }}>
          <BrandLogo brand={service.brand} color={service.color} name={service.name} size={40} />
          <div>
            <div style={{ fontWeight: 700, fontSize: 15 }}>{service.name}</div>
            <div className="muted" style={{ fontSize: 12 }}>{service.cat}</div>
          </div>
        </div>
        <span className="pill neutral">Disconnected</span>
      </div>

      <p style={{ margin: "0 0 14px", fontSize: 13, color: "var(--gray-700)", lineHeight: 1.5 }}>{service.desc}</p>

      <div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", padding: "10px 0", borderTop: "1px solid var(--gray-100)", borderBottom: "1px solid var(--gray-100)", marginBottom: 14 }}>
        <span className="muted" style={{ fontSize: 13, fontWeight: 500 }}>Auth Type</span>
        <span className="pill info">{authType}</span>
      </div>

      <div className="field">
        <label style={{ fontSize: 12 }}>{authType === "OAuth" ? "Email / Account" : authType === "API key" ? "API key" : "Connection string"}</label>
        <input
          className="input"
          value={email}
          onChange={(e) => { setEmail(e.target.value); setShowError(false); }}
          style={{ borderColor: showError ? "var(--error-500)" : undefined }}
        />
        {showError && (
          <div style={{ display: "flex", alignItems: "center", gap: 6, color: "var(--error-600)", fontSize: 12, marginTop: 4, fontWeight: 600 }}>
            <Icon name="alert-triangle" size={12} stroke={2.4} /> Account does not exist. Try again or contact your administrator.
          </div>
        )}
      </div>

      <button className="btn primary" onClick={handleConnect} disabled={phase !== "add"} style={{ width: "100%", marginTop: 14, justifyContent: "center" }}>
        {phase === "connecting" ? <><Icon name="loader-2" size={16} className="spin" /> Connecting…</> : <>Connect Now <Icon name="arrow-right" size={16} /></>}
      </button>
      <style>{`.spin { animation: spin 1s linear infinite; } @keyframes spin { to { transform: rotate(360deg); } }`}</style>
    </div>
  );
}

function ConnectingOverlay({ adding }) {
  return (
    <div style={{ position: "fixed", inset: 0, background: "rgba(255,255,255,0.92)", zIndex: 70, display: "grid", placeItems: "center" }}>
      <div style={{ textAlign: "center", maxWidth: 480 }}>
        <div style={{ width: 80, height: 80, margin: "0 auto 18px", position: "relative" }}>
          <div style={{
            width: 80, height: 80, borderRadius: 24,
            background: "var(--green-50)", display: "grid", placeItems: "center",
          }}>
            {adding && <BrandLogo brand={adding.brand} color={adding.color} name={adding.name} size={48} />}
          </div>
          <svg style={{ position: "absolute", inset: -8, animation: "spin 1.2s linear infinite" }} width="96" height="96" viewBox="0 0 96 96">
            <circle cx="48" cy="48" r="44" fill="none" stroke="var(--green-100)" strokeWidth="3" />
            <circle cx="48" cy="48" r="44" fill="none" stroke="var(--brand-700)" strokeWidth="3" strokeDasharray="50 220" strokeLinecap="round" />
          </svg>
        </div>
        <h2 style={{ fontFamily: "var(--serif)", fontSize: 30, color: "var(--brand-700)", margin: "0 0 6px" }}>Connecting integration</h2>
        <p className="muted" style={{ margin: 0 }}>Kindly wait, your {adding?.name} integration is connecting.</p>
      </div>
    </div>
  );
}

function SuccessModal({ onClose }) {
  return (
    <div className="modal-bg" style={{ zIndex: 80 }} onMouseDown={(e) => { if (e.target === e.currentTarget) onClose(); }}>
      <div className="modal" style={{ maxWidth: 520, padding: "48px 32px 32px", textAlign: "center" }}>
        <div style={{
          width: 96, height: 96, margin: "0 auto 22px", position: "relative",
          background: "var(--green-50)", borderRadius: "50%",
          display: "grid", placeItems: "center",
        }}>
          <div style={{
            width: 72, height: 72, borderRadius: "50%", background: "var(--brand-700)",
            display: "grid", placeItems: "center", color: "#fff",
          }}>
            <Icon name="link" size={32} stroke={2.2} />
          </div>
        </div>
        <h2 style={{ fontFamily: "var(--serif)", fontSize: 28, color: "var(--brand-700)", margin: "0 0 10px" }}>Integration Connected Successfully</h2>
        <p className="muted" style={{ margin: "0 0 24px", maxWidth: 360, marginLeft: "auto", marginRight: "auto" }}>Congratulations! You have successfully synced a third-party integration to your NutriDMS account.</p>
        <button className="btn primary" onClick={onClose} style={{ minWidth: 220, justifyContent: "center" }}>
          <Icon name="corner-down-left" size={16} /> Return to Dashboard
        </button>
      </div>
    </div>
  );
}

Object.assign(window, { IntegrationsScreen });
