/* components/admin/Admin.jsx — internal leasing admin dashboard.
   Zero-build: plain <script type="text/babel">, shared global scope.
   Globals used (do NOT redefine): React, ReactDOM, Portal, Icon, CenterLoad,
   Field, window.portalSupabase (client OR null=DEMO), window.portalAnalytics.
   Routes (via App.jsx switch): admin | admin-detail | admin-users. */
/* eslint-disable */
const { useState: useAd, useEffect: useEAd, useMemo: useMAd, useCallback: useCAd } = React;

/* ---------------- status vocab ---------------- */
const ADMIN_STATUSES = [
  "lead", "qualified", "stage2_in_progress", "submitted",
  "reviewing", "info_requested", "approved", "declined", "withdrawn",
];
const ADMIN_STATUS_LABEL = {
  lead: "Lead",
  qualified: "Qualified",
  stage2_in_progress: "Stage 2 — In progress",
  submitted: "Submitted",
  reviewing: "Reviewing",
  info_requested: "Info requested",
  approved: "Approved",
  declined: "Declined",
  withdrawn: "Withdrawn",
};
function adStatusLabel(s) { return ADMIN_STATUS_LABEL[s] || (s || "—"); }
function adStatusTag(s) { return "status-tag status-" + (s || "lead"); }

/* ---------------- helpers ---------------- */
function adGet(obj, path, fb) {
  if (!obj) return fb;
  var parts = String(path).split(".");
  var node = obj;
  for (var i = 0; i < parts.length; i++) {
    if (node == null) return fb;
    node = node[parts[i]];
  }
  return node == null ? fb : node;
}

function adRelTime(iso) {
  if (!iso) return "—";
  var then = new Date(iso).getTime();
  if (isNaN(then)) return "—";
  var secs = Math.floor((Date.now() - then) / 1000);
  if (secs < 0) secs = 0;
  if (secs < 60) return "just now";
  var mins = Math.floor(secs / 60);
  if (mins < 60) return mins + "m ago";
  var hrs = Math.floor(mins / 60);
  if (hrs < 24) return hrs + "h ago";
  var days = Math.floor(hrs / 24);
  if (days < 30) return days + "d ago";
  var months = Math.floor(days / 30);
  if (months < 12) return months + "mo ago";
  return Math.floor(months / 12) + "y ago";
}

function adDate(iso) {
  if (!iso) return "—";
  var d = new Date(iso);
  if (isNaN(d.getTime())) return "—";
  return d.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" });
}

function adFileSize(bytes) {
  if (bytes == null) return "";
  var n = Number(bytes);
  if (!n) return "";
  if (n < 1024) return n + " B";
  if (n < 1048576) return (n / 1024).toFixed(0) + " KB";
  return (n / 1048576).toFixed(1) + " MB";
}

function adYN(v) { return v === true ? "Yes" : v === false ? "No" : "—"; }
function adDays(since, until) {
  if (!since) return null;
  var a = new Date(since).getTime();
  var b = until ? new Date(until).getTime() : Date.now();
  if (isNaN(a) || isNaN(b)) return null;
  return Math.floor((b - a) / 86400000);
}

/* ---------------- DEMO sample data (505 Rose) ---------------- */
function adDemoApps() {
  var now = Date.now();
  var ago = function (days) { return new Date(now - days * 86400000).toISOString(); };
  return [
    {
      id: "demo-1", tenant_id: "505rose", status: "submitted",
      concept_name: "Cabin & Pine Brewing", use_type: "Brewery / Taproom",
      target_sf_range: "3,000 – 4,500 SF", free_text_notes: "Looking for a community-first taproom with a patio. Big draw on weekends.",
      applicants: { full_name: "Marcus Trujillo", email: "marcus@cabinandpine.co", phone: "(720) 555-0142" },
      properties: { name: "505 Rose" },
      entity_legal_name: "Cabin & Pine Brewing LLC", entity_dba: "Cabin & Pine Brewing",
      entity_structure: "LLC", entity_state: "CO", ein: "84-2910374",
      year_founded: 2019, naics_code: "312120", years_in_business: 6, ft_employees: 11, pt_employees: 8,
      annual_revenue_range: "$1M – $2.5M", annual_revenue_proj_range: "$2.5M – $5M",
      gross_margin_range: "60 – 70%", cash_reserves_range: "$250K – $500K",
      monthly_rent_budget_range: "$9K – $12K", buildout_cost_range: "$350K – $500K",
      buildout_finance_method: "SBA 7(a) loan + owner equity",
      hours_of_operation: "Tue–Sun 11a–11p, closed Mondays",
      business_plan_summary: "Second location for an established Denver craft brewery. Anchor tenant draw with rotating taps, a kitchen partnership, and weekend live music. Targets the 25–45 neighborhood demo.",
      disclosure_bankruptcy_y: false, disclosure_foreclosure_y: false,
      disclosure_eviction_y: false, disclosure_assignment_y: true,
      disclosure_assignment_explain: "Assigned a prior lease in 2021 when consolidating to one location; landlord released in full.",
      certify_accuracy: true, docusign_envelope_id: "env_8f31c0", signed_at: ago(2),
      stage1_submitted_at: ago(14), stage2_submitted_at: ago(2), invited_at: ago(12),
      created_at: ago(14), updated_at: ago(2),
      _owners: [
        { full_name: "Marcus Trujillo", title: "Managing Member", ownership_pct: 60, personal_guaranty: true, email: "marcus@cabinandpine.co" },
        { full_name: "Dana Reyes", title: "Member / Head Brewer", ownership_pct: 40, personal_guaranty: true, email: "dana@cabinandpine.co" },
      ],
      _locations: [
        { address: "1820 Larimer St, Denver, CO", sf: 2800, year_opened: 2019, current_rent: "$8,400/mo", lease_type: "NNN", lease_expiration: "2027-08-31", annual_sales_range: "$1M – $2.5M" },
      ],
      _references: [
        { ref_kind: "landlord", company: "Larimer Holdings", contact_name: "Pat Quill", phone: "(303) 555-0190", email: "pat@larimerholdings.com" },
        { ref_kind: "bank", company: "FirstBank Colorado", contact_name: "Lena Ott", phone: "(303) 555-0177", email: "lott@firstbank.com" },
        { ref_kind: "vendor", company: "Rocky Mtn Malt Co.", contact_name: "Jim Hale", phone: "(720) 555-0123", email: "jim@rmmalt.com" },
      ],
      _documents: [
        { id: "d1", document_type: "business_tax", source: "upload", filename: "2024-business-return.pdf", file_size_bytes: 482000, storage_path: "demo-1/2024-business-return.pdf" },
        { id: "d2", document_type: "pnl", source: "upload", filename: "ytd-pnl-2025.pdf", file_size_bytes: 191000, storage_path: "demo-1/ytd-pnl-2025.pdf" },
        { id: "d3", document_type: "plaid_assets", source: "plaid", filename: "FirstBank — operating acct (Plaid)", file_size_bytes: null, storage_path: null, plaid_item_id: "itm_92x" },
        { id: "d4", document_type: "formation", source: "upload", filename: "articles-of-organization.pdf", file_size_bytes: 88000, storage_path: "demo-1/articles-of-organization.pdf" },
      ],
      _events: [
        { event_type: "stage2_submitted", step: "H", created_at: ago(2) },
        { event_type: "docusign_signed", step: "H", created_at: ago(2) },
        { event_type: "step_completed", step: "G", created_at: ago(3) },
        { event_type: "stage2_started", step: "A", created_at: ago(11) },
        { event_type: "stage1_submitted", step: null, created_at: ago(14) },
      ],
      _reviews: [
        { action: "note", note: "Strong concept — Sandy likes the patio activation. Verify SBA pre-approval before LOI.", admin_name: "Ross Carpenter", created_at: ago(1) },
        { action: "status_change", from_status: "qualified", to_status: "submitted", admin_name: "Ross Carpenter", created_at: ago(2) },
        { action: "invite_sent", to_status: "qualified", admin_name: "Ross Carpenter", created_at: ago(12) },
      ],
    },
    {
      id: "demo-2", tenant_id: "505rose", status: "reviewing",
      concept_name: "Rosewood Table", use_type: "Restaurant — Full Service",
      target_sf_range: "2,500 – 3,500 SF", free_text_notes: "Farm-to-table dinner concept, chef-driven.",
      applicants: { full_name: "Priya Anand", email: "priya@rosewoodtable.com", phone: "(310) 555-0118" },
      properties: { name: "505 Rose" },
      entity_legal_name: "Rosewood Hospitality Inc.", entity_dba: "Rosewood Table",
      entity_structure: "S-Corp", entity_state: "CA", ein: "47-1182093",
      year_founded: 2016, naics_code: "722511", years_in_business: 9, ft_employees: 22, pt_employees: 14,
      annual_revenue_range: "$2.5M – $5M", annual_revenue_proj_range: "$2.5M – $5M",
      gross_margin_range: "55 – 65%", cash_reserves_range: "$100K – $250K",
      monthly_rent_budget_range: "$7K – $9K", buildout_cost_range: "$250K – $350K",
      buildout_finance_method: "Owner equity + equipment lease",
      hours_of_operation: "Wed–Sun 5p–10p",
      business_plan_summary: "Established chef expanding from one successful location. Reservations-driven, 70 covers, full bar.",
      disclosure_bankruptcy_y: false, disclosure_foreclosure_y: false,
      disclosure_eviction_y: false, disclosure_assignment_y: false,
      certify_accuracy: true,
      stage1_submitted_at: ago(9), stage2_submitted_at: ago(4), invited_at: ago(8),
      created_at: ago(9), updated_at: ago(1),
      _owners: [{ full_name: "Priya Anand", title: "President", ownership_pct: 100, personal_guaranty: true, email: "priya@rosewoodtable.com" }],
      _locations: [{ address: "44 Abbot Kinney Blvd, Venice, CA", sf: 2200, year_opened: 2016, current_rent: "$6,900/mo", lease_type: "NNN", lease_expiration: "2026-12-31", annual_sales_range: "$2.5M – $5M" }],
      _references: [{ ref_kind: "landlord", company: "AK Retail Partners", contact_name: "Sam Kohl", phone: "(310) 555-0144", email: "sam@akretail.com" }],
      _documents: [
        { id: "d5", document_type: "business_tax", source: "upload", filename: "rosewood-2024-return.pdf", file_size_bytes: 511000, storage_path: "demo-2/rosewood-2024-return.pdf" },
        { id: "d6", document_type: "id", source: "upload", filename: "anand-id.jpg", file_size_bytes: 240000, storage_path: "demo-2/anand-id.jpg" },
      ],
      _events: [
        { event_type: "stage2_submitted", step: "H", created_at: ago(4) },
        { event_type: "stage1_submitted", step: null, created_at: ago(9) },
      ],
      _reviews: [
        { action: "status_change", from_status: "submitted", to_status: "reviewing", admin_name: "Ross Carpenter", created_at: ago(1) },
      ],
    },
    {
      id: "demo-3", tenant_id: "505rose", status: "stage2_in_progress",
      concept_name: "Tidewater Coffee", use_type: "Café / Coffee",
      target_sf_range: "1,200 – 1,800 SF", free_text_notes: "Specialty coffee + light pastry.",
      applicants: { full_name: "Owen Park", email: "owen@tidewatercoffee.com", phone: "(206) 555-0167" },
      properties: { name: "505 Rose" },
      entity_legal_name: "Tidewater Coffee LLC", entity_structure: "LLC", entity_state: "WA",
      year_founded: 2022, years_in_business: 3, ft_employees: 4, pt_employees: 6,
      annual_revenue_range: "$500K – $1M", monthly_rent_budget_range: "$4K – $6K",
      certify_accuracy: false,
      stage1_submitted_at: ago(5), invited_at: ago(4),
      created_at: ago(5), updated_at: ago(1),
      _owners: [], _locations: [], _references: [], _documents: [],
      _events: [
        { event_type: "stage2_started", step: "B", created_at: ago(1) },
        { event_type: "stage1_submitted", step: null, created_at: ago(5) },
      ],
      _reviews: [{ action: "invite_sent", to_status: "qualified", admin_name: "Ross Carpenter", created_at: ago(4) }],
    },
    {
      id: "demo-4", tenant_id: "505rose", status: "lead",
      concept_name: "Bloom & Stem", use_type: "Retail — Florist / Gift",
      target_sf_range: "800 – 1,200 SF", free_text_notes: "Boutique florist, wants high-foot-traffic corner.",
      applicants: { full_name: "Sofia Cruz", email: "hello@bloomandstem.com", phone: "(323) 555-0155" },
      properties: { name: "505 Rose" },
      certify_accuracy: false,
      stage1_submitted_at: ago(2), created_at: ago(2), updated_at: ago(2),
      _owners: [], _locations: [], _references: [], _documents: [],
      _events: [{ event_type: "stage1_submitted", step: null, created_at: ago(2) }],
      _reviews: [],
    },
    {
      id: "demo-5", tenant_id: "505rose", status: "approved",
      concept_name: "Northline Provisions", use_type: "Retail — Grocer / Market",
      target_sf_range: "4,000 – 6,000 SF", free_text_notes: "Neighborhood market + deli.",
      applicants: { full_name: "Greg Halloran", email: "greg@northlineprov.com", phone: "(720) 555-0188" },
      properties: { name: "505 Rose" },
      entity_legal_name: "Northline Provisions LLC", entity_structure: "LLC", entity_state: "CO",
      years_in_business: 12, certify_accuracy: true,
      stage1_submitted_at: ago(40), stage2_submitted_at: ago(30),
      created_at: ago(40), updated_at: ago(20),
      _owners: [], _locations: [], _references: [], _documents: [],
      _events: [{ event_type: "stage2_submitted", step: "H", created_at: ago(30) }],
      _reviews: [{ action: "status_change", from_status: "reviewing", to_status: "approved", admin_name: "Ross Carpenter", created_at: ago(20) }],
    },
    {
      id: "demo-6", tenant_id: "505rose", status: "info_requested",
      concept_name: "Pivot Fitness Studio", use_type: "Service — Fitness",
      target_sf_range: "2,000 – 3,000 SF", free_text_notes: "Boutique strength + recovery studio.",
      applicants: { full_name: "Dani Okafor", email: "dani@pivotfit.studio", phone: "(310) 555-0133" },
      properties: { name: "505 Rose" },
      entity_legal_name: "Pivot Fitness LLC", entity_structure: "LLC", entity_state: "CA",
      years_in_business: 4, certify_accuracy: true,
      disclosure_eviction_y: true, disclosure_eviction_explain: "Prior studio space — landlord-tenant dispute over HVAC repair; settled and vacated voluntarily 2023.",
      stage1_submitted_at: ago(18), stage2_submitted_at: ago(7),
      created_at: ago(18), updated_at: ago(3),
      _owners: [], _locations: [], _references: [], _documents: [],
      _events: [{ event_type: "stage2_submitted", step: "H", created_at: ago(7) }],
      _reviews: [{ action: "status_change", from_status: "reviewing", to_status: "info_requested", note: "Need the 2024 business return and an explanation on the prior eviction.", admin_name: "Ross Carpenter", created_at: ago(3) }],
    },
  ];
}

function adDemoAdmins() {
  return [
    { user_id: "u-ross", full_name: "Ross Carpenter", email: "ross@newmarkmerrill.com", role: "leasing", is_super_admin: true, active: true },
    { user_id: "u-1", full_name: "Sandy Sigal", email: "sandy@newmarkmerrill.com", role: "executive", is_super_admin: true, active: true },
    { user_id: "u-2", full_name: "Jamie Chen", email: "jamie@newmarkmerrill.com", role: "leasing", is_super_admin: false, active: true },
    { user_id: "u-3", full_name: "Marcus Webb", email: "marcus@newmarkmerrill.com", role: "leasing", is_super_admin: false, active: true },
    { user_id: "u-4", full_name: "Tara Liu", email: "tara@newmarkmerrill.com", role: "analyst", is_super_admin: false, active: true },
    { user_id: "u-5", full_name: "Devon Pratt", email: "devon@newmarkmerrill.com", role: "leasing", is_super_admin: false, active: false },
    { user_id: "u-6", full_name: "Aisha Bello", email: "aisha@newmarkmerrill.com", role: "analyst", is_super_admin: false, active: true },
  ];
}

/* ============================================================
   Root: Admin chrome + auth gate + view switch
   ============================================================ */
function Admin({ route }) {
  const sb = window.portalSupabase;
  const demo = !sb;

  const [authState, setAuthState] = useAd({ loading: !demo, signedIn: demo, isAdmin: demo, uid: null, email: null, isSuper: demo });

  useEAd(function () {
    if (demo) return;
    var alive = true;
    sb.auth.getSession().then(function (res) {
      var session = res && res.data && res.data.session;
      if (!session || !session.user) {
        if (alive) setAuthState({ loading: false, signedIn: false, isAdmin: false, uid: null, email: null, isSuper: false });
        return;
      }
      var uid = session.user.id;
      sb.from("admin_users").select("user_id, is_super_admin, active").eq("user_id", uid).maybeSingle()
        .then(function (r) {
          if (!alive) return;
          var row = r && r.data;
          setAuthState({
            loading: false, signedIn: true,
            isAdmin: !!(row && row.active), uid: uid,
            email: session.user.email,
            isSuper: !!(row && row.is_super_admin),
          });
        });
    });
    return function () { alive = false; };
  }, []);

  if (authState.loading) return <AdminShell route={route}><CenterLoad label="Checking access" /></AdminShell>;

  if (!demo && (!authState.signedIn || !authState.isAdmin)) {
    return <AdminShell route={route}><AdminSignIn sb={sb} signedInNotAdmin={authState.signedIn && !authState.isAdmin} /></AdminShell>;
  }

  let view;
  if (route.route === "admin-detail") view = <AdminDetail id={route.params.id} demo={demo} auth={authState} />;
  else if (route.route === "admin-users") view = <AdminUsers demo={demo} auth={authState} />;
  else view = <AdminList demo={demo} />;

  return <AdminShell route={route}>{view}</AdminShell>;
}

function AdminShell({ route, children }) {
  const brand = Portal.brand || {};
  const at = route.route;
  return (
    <div className="admin-shell">
      <header className="admin-top">
        <div className="at-brand">{brand.name || "Portal"}<b>· Leasing</b></div>
        <nav>
          <a href="#/admin" className={Portal.cx((at === "admin" || at === "admin-detail") && "active")}>Applications</a>
          <a href="#/admin/users" className={Portal.cx(at === "admin-users" && "active")}>Admins</a>
          <a href="#/apply">View portal</a>
        </nav>
      </header>
      <div className="admin-wrap">{children}</div>
    </div>
  );
}

/* ---------------- sign-in (magic link) ---------------- */
function AdminSignIn({ sb, signedInNotAdmin }) {
  const [email, setEmail] = useAd("");
  const [touched, setTouched] = useAd(false);
  const [sending, setSending] = useAd(false);
  const [sent, setSent] = useAd(false);
  const [err, setErr] = useAd(null);

  const error = Portal.validators.email(email);

  function send() {
    setTouched(true);
    if (error) return;
    setSending(true); setErr(null);
    // Route back to the admin dashboard after the magic link authenticates.
    try { localStorage.setItem("portal_post_login", "#/admin"); } catch (e) {}
    sb.auth.signInWithOtp({ email: email, options: { emailRedirectTo: window.location.origin + window.location.pathname } })
      .then(function (r) {
        setSending(false);
        if (r && r.error) { setErr(r.error.message || "Could not send link"); return; }
        setSent(true);
      })
      .catch(function (e) { setSending(false); setErr((e && e.message) || "Could not send link"); });
  }

  return (
    <div className="admin-detail-grid" style={{ gridTemplateColumns: "1fr", maxWidth: 520, margin: "40px auto" }}>
      <div className="detail-card">
        <div className="eyebrow brick" style={{ marginBottom: 18 }}><Icon name="shield" size={14} /> Admin sign-in</div>
        {signedInNotAdmin && (
          <div className="status-tag status-declined" style={{ display: "inline-block", marginBottom: 16 }}>
            This account isn't on the admin list
          </div>
        )}
        {sent ? (
          <div>
            <h3 style={{ color: "var(--ink)" }}><Icon name="check" size={16} /> Check your email</h3>
            <p style={{ fontFamily: "var(--sans)", fontSize: 14, color: "var(--ink-2)" }}>
              We sent a sign-in link to <b>{email}</b>. Open it on this device to enter the dashboard.
            </p>
          </div>
        ) : (
          <div>
            <p style={{ fontFamily: "var(--sans)", fontSize: 14, color: "var(--ink-2)", marginBottom: 16 }}>
              Enter your work email and we'll send a one-time sign-in link.
            </p>
            <Field name="email" label="Work email" type="email" required
              value={email} error={error} touched={touched}
              onChange={function (n, v) { setEmail(v); }} onBlur={function () { setTouched(true); }} />
            {err && <div className="field-err" style={{ marginBottom: 12 }}><Icon name="alert" size={13} /> {err}</div>}
            <button className="btn block" disabled={sending} onClick={send}>
              {sending ? "Sending…" : "Send sign-in link"} <Icon name="arrow" size={16} />
            </button>
          </div>
        )}
      </div>
    </div>
  );
}

/* ============================================================
   View 1 — Applications list
   ============================================================ */
function AdminList({ demo }) {
  const [rows, setRows] = useAd(null);
  const [status, setStatus] = useAd("all");
  const [useType, setUseType] = useAd("all");
  const [q, setQ] = useAd("");

  useEAd(function () {
    var alive = true;
    if (demo) { setRows(adDemoApps()); return; }
    var sb = window.portalSupabase;
    sb.from("applications")
      .select("*, applicants(full_name,email,phone), properties(name)")
      .order("created_at", { ascending: false })
      .then(function (r) {
        if (!alive) return;
        setRows((r && r.data) || []);
      });
    return function () { alive = false; };
  }, [demo]);

  const useTypes = useMAd(function () {
    if (!rows) return [];
    var set = {};
    rows.forEach(function (a) { if (a.use_type) set[a.use_type] = true; });
    return Object.keys(set).sort();
  }, [rows]);

  const filtered = useMAd(function () {
    if (!rows) return [];
    var needle = q.trim().toLowerCase();
    return rows.filter(function (a) {
      if (status !== "all" && a.status !== status) return false;
      if (useType !== "all" && a.use_type !== useType) return false;
      if (needle) {
        var ap = a.applicants || {};
        var hay = [a.concept_name, ap.full_name, ap.email].filter(Boolean).join(" ").toLowerCase();
        if (hay.indexOf(needle) === -1) return false;
      }
      return true;
    });
  }, [rows, status, useType, q]);

  const kpis = useMAd(function () {
    var out = { newWk: 0, await: 0, prog: 0, appr: 0 };
    if (!rows) return out;
    var weekAgo = Date.now() - 7 * 86400000;
    rows.forEach(function (a) {
      if (a.created_at && new Date(a.created_at).getTime() >= weekAgo) out.newWk++;
      if (a.status === "submitted" || a.status === "reviewing") out.await++;
      if (a.status === "stage2_in_progress") out.prog++;
      if (a.status === "approved") out.appr++;
    });
    return out;
  }, [rows]);

  if (!rows) return <CenterLoad label="Loading applications" />;

  return (
    <div>
      <div className="kpi-grid">
        <div className="kpi"><div className="kv">{kpis.newWk}</div><div className="kl">New this week</div></div>
        <div className="kpi"><div className="kv">{kpis.await}</div><div className="kl">Awaiting review</div></div>
        <div className="kpi"><div className="kv">{kpis.prog}</div><div className="kl">In progress</div></div>
        <div className="kpi"><div className="kv">{kpis.appr}</div><div className="kl">Approved</div></div>
      </div>

      <div className="admin-filters">
        <select value={status} onChange={function (e) { setStatus(e.target.value); }}>
          <option value="all">All statuses</option>
          {ADMIN_STATUSES.map(function (s) { return <option key={s} value={s}>{adStatusLabel(s)}</option>; })}
        </select>
        <select value={useType} onChange={function (e) { setUseType(e.target.value); }}>
          <option value="all">All use types</option>
          {useTypes.map(function (u) { return <option key={u} value={u}>{u}</option>; })}
        </select>
        <input type="text" placeholder="Search concept, name, or email…" value={q}
          onChange={function (e) { setQ(e.target.value); }} style={{ flex: "1 1 240px" }} />
      </div>

      {filtered.length === 0 ? (
        <div className="empty-state">No applications match these filters.</div>
      ) : (
        <table className="app-table">
          <thead>
            <tr>
              <th>Applicant</th><th>Concept</th><th>Use</th><th>Target SF</th><th>Status</th><th>Submitted</th>
            </tr>
          </thead>
          <tbody>
            {filtered.map(function (a) {
              var ap = a.applicants || {};
              var submitted = a.stage2_submitted_at || a.stage1_submitted_at || a.created_at;
              return (
                <tr key={a.id} onClick={function () { Portal.navigate("#/admin/application/" + a.id); }}>
                  <td>
                    <div className="ap-name">{ap.full_name || "—"}</div>
                    <div style={{ fontSize: 12, color: "var(--muted)" }}>{ap.email || ""}</div>
                  </td>
                  <td>{a.concept_name || "—"}</td>
                  <td>{a.use_type || "—"}</td>
                  <td>{a.target_sf_range || "—"}</td>
                  <td><span className={adStatusTag(a.status)}>{adStatusLabel(a.status)}</span></td>
                  <td>{adRelTime(submitted)}</td>
                </tr>
              );
            })}
          </tbody>
        </table>
      )}
    </div>
  );
}

/* ============================================================
   View 2 — Application detail + actions
   ============================================================ */
function AdminDetail({ id, demo, auth }) {
  const [app, setApp] = useAd(null);
  const [loading, setLoading] = useAd(true);
  const [busy, setBusy] = useAd(false);
  const [noteText, setNoteText] = useAd("");
  const [reviews, setReviews] = useAd([]);
  const [events, setEvents] = useAd([]);

  const loadDetail = useCAd(function () {
    if (demo) {
      var found = adDemoApps().filter(function (a) { return a.id === id; })[0] || null;
      setApp(found);
      setReviews(found ? (found._reviews || []) : []);
      setEvents(found ? (found._events || []) : []);
      setLoading(false);
      return;
    }
    var sb = window.portalSupabase;
    setLoading(true);
    sb.from("applications")
      .select("*, applicants(full_name,email,phone,best_time_to_reach,sms_opt_in), properties(name), application_owners(*), application_locations(*), application_references(*), documents(*)")
      .eq("id", id).maybeSingle()
      .then(function (r) {
        var d = r && r.data;
        if (d) {
          d._owners = d.application_owners || [];
          d._locations = d.application_locations || [];
          d._references = d.application_references || [];
          d._documents = d.documents || [];
        }
        setApp(d || null);
        setLoading(false);
      });
    sb.from("admin_reviews").select("*").eq("application_id", id).order("created_at", { ascending: false })
      .then(function (r) { setReviews((r && r.data) || []); });
    sb.from("events").select("event_type, step, field, created_at").eq("application_id", id)
      .order("created_at", { ascending: false }).limit(40)
      .then(function (r) { setEvents((r && r.data) || []); });
  }, [id, demo]);

  useEAd(function () { loadDetail(); }, [loadDetail]);

  function writeReview(row) {
    var entry = Object.assign({ application_id: id, admin_id: auth && auth.uid }, row);
    if (demo) {
      setReviews(function (prev) { return [Object.assign({ admin_name: "You", created_at: new Date().toISOString() }, entry)].concat(prev); });
      return Promise.resolve();
    }
    var sb = window.portalSupabase;
    return sb.from("admin_reviews").insert(entry).then(function () {
      return sb.from("admin_reviews").select("*").eq("application_id", id).order("created_at", { ascending: false })
        .then(function (r) { setReviews((r && r.data) || []); });
    });
  }

  function transition(toStatus, action, extra, edgeFn, edgeBody) {
    if (busy) return;
    setBusy(true);
    var fromStatus = app.status;
    var patch = Object.assign({ status: toStatus }, extra || {});

    function finish() {
      setApp(function (prev) { return Object.assign({}, prev, patch); });
      writeReview({ action: action || "status_change", from_status: fromStatus, to_status: toStatus, note: (extra && extra.__note) || null })
        .then(function () { setBusy(false); });
    }

    if (demo) { finish(); return; }
    var sb = window.portalSupabase;
    var clean = Object.assign({}, patch); delete clean.__note;
    sb.from("applications").update(clean).eq("id", id).then(function () {
      if (edgeFn) {
        try { sb.functions.invoke(edgeFn, { body: edgeBody || { application_id: id } }).catch(function () {}); } catch (e) {}
      }
      finish();
    });
  }

  function onSendStage2Invite() {
    transition("qualified", "invite_sent", { invited_at: new Date().toISOString() }, "send-stage2-invite", { application_id: id });
  }
  function onMarkReviewing() { transition("reviewing", "status_change", null, null, null); }
  function onRequestDocs() {
    var note = window.prompt("What documents or info do you need? (sent to the applicant)");
    if (note == null) return;
    transition("info_requested", "doc_requested", { __note: note }, "request-documents", { application_id: id, note: note });
  }
  function onApprove() {
    if (!window.confirm("Approve this application? The applicant will be notified.")) return;
    transition("approved", "status_change", null, "send-status-update", { application_id: id, status: "approved" });
  }
  function onDecline() {
    if (!window.confirm("Decline this application? The applicant will be notified.")) return;
    transition("declined", "status_change", null, "send-status-update", { application_id: id, status: "declined" });
  }
  function onWithdraw() {
    if (!window.confirm("Mark this application withdrawn?")) return;
    transition("withdrawn", "status_change", null, null, null);
  }

  function addNote() {
    var t = noteText.trim();
    if (!t) return;
    writeReview({ action: "note", note: t }).then(function () { setNoteText(""); });
  }

  if (loading) return <CenterLoad label="Loading application" />;
  if (!app) return <div className="empty-state">Application not found. <a href="#/admin" style={{ textDecoration: "underline" }}>Back to list</a></div>;

  const ap = app.applicants || {};
  const prop = app.properties || {};
  const owners = app._owners || [];
  const locations = app._locations || [];
  const references = app._references || [];
  const documents = app._documents || [];
  const noteReviews = reviews.filter(function (r) { return r.action === "note"; });

  const disclosures = [
    { k: "Bankruptcy", y: app.disclosure_bankruptcy_y, x: app.disclosure_bankruptcy_explain },
    { k: "Foreclosure", y: app.disclosure_foreclosure_y, x: app.disclosure_foreclosure_explain },
    { k: "Eviction", y: app.disclosure_eviction_y, x: app.disclosure_eviction_explain },
    { k: "Lease assignment / default", y: app.disclosure_assignment_y, x: app.disclosure_assignment_explain },
  ];

  return (
    <div>
      <a href="#/admin" style={{ fontFamily: "var(--mono)", fontSize: 11, letterSpacing: ".12em", textTransform: "uppercase", color: "var(--muted)", display: "inline-block", marginBottom: 18 }}>← All applications</a>
      <div className="admin-detail-grid">
        {/* LEFT */}
        <div>
          <div className="detail-card">
            <h3>Summary</h3>
            <dl className="dl">
              <dt>Applicant</dt><dd>{ap.full_name || "—"}</dd>
              <dt>Email</dt><dd>{ap.email || "—"}</dd>
              <dt>Phone</dt><dd>{ap.phone ? Portal.formatPhone(ap.phone) : "—"}</dd>
              <dt>Best time</dt><dd>{ap.best_time_to_reach || "—"}</dd>
              <dt>Property</dt><dd>{prop.name || "—"}</dd>
              <dt>Concept</dt><dd>{app.concept_name || "—"}</dd>
              <dt>Use type</dt><dd>{app.use_type || "—"}</dd>
              <dt>Target SF</dt><dd>{app.target_sf_range || "—"}</dd>
              <dt>Status</dt><dd><span className={adStatusTag(app.status)}>{adStatusLabel(app.status)}</span></dd>
              <dt>Created</dt><dd>{adDate(app.created_at)}</dd>
              <dt>Stage 1 submitted</dt><dd>{adDate(app.stage1_submitted_at)}</dd>
              <dt>Stage 2 submitted</dt><dd>{adDate(app.stage2_submitted_at)}</dd>
              <dt>Invited</dt><dd>{adDate(app.invited_at)}</dd>
              <dt>E-signed</dt><dd>{app.signed_at ? adDate(app.signed_at) + (app.docusign_envelope_id ? " · " + app.docusign_envelope_id : "") : "—"}</dd>
            </dl>
            {app.free_text_notes && <p style={{ fontFamily: "var(--sans)", fontSize: 14, color: "var(--ink-2)", marginTop: 16 }}>{app.free_text_notes}</p>}
          </div>

          <div className="detail-card">
            <h3>Entity &amp; Business</h3>
            <dl className="dl">
              <dt>Legal name</dt><dd>{app.entity_legal_name || "—"}</dd>
              <dt>DBA</dt><dd>{app.entity_dba || "—"}</dd>
              <dt>Structure</dt><dd>{app.entity_structure || "—"}</dd>
              <dt>State</dt><dd>{app.entity_state || "—"}</dd>
              <dt>EIN</dt><dd>{app.ein || "—"}</dd>
              <dt>Year founded</dt><dd>{app.year_founded || "—"}</dd>
              <dt>NAICS</dt><dd>{app.naics_code || "—"}</dd>
              <dt>Years in business</dt><dd>{app.years_in_business != null ? app.years_in_business : "—"}</dd>
              <dt>Employees</dt><dd>{(app.ft_employees != null ? app.ft_employees : "—") + " FT · " + (app.pt_employees != null ? app.pt_employees : "—") + " PT"}</dd>
              <dt>Hours</dt><dd>{app.hours_of_operation || "—"}</dd>
            </dl>
            {app.business_plan_summary && <p style={{ fontFamily: "var(--sans)", fontSize: 14, color: "var(--ink-2)", marginTop: 16 }}>{app.business_plan_summary}</p>}
          </div>

          <div className="detail-card">
            <h3>Owners &amp; Guarantors</h3>
            {owners.length === 0 ? <p className="dl" style={{ color: "var(--muted)" }}>None recorded.</p> : (
              <dl className="dl">
                {owners.map(function (o, i) {
                  return (
                    <React.Fragment key={i}>
                      <dt>{o.full_name || "Owner " + (i + 1)}</dt>
                      <dd>
                        {(o.title || "—")}{o.ownership_pct != null ? " · " + o.ownership_pct + "%" : ""}
                        {o.personal_guaranty ? " · " : ""}{o.personal_guaranty ? <span className="pill outline" style={{ fontSize: 9 }}>PG</span> : null}
                        {o.email ? <div style={{ fontSize: 12, color: "var(--muted)" }}>{o.email}</div> : null}
                      </dd>
                    </React.Fragment>
                  );
                })}
              </dl>
            )}
          </div>

          <div className="detail-card">
            <h3>Existing Locations</h3>
            {locations.length === 0 ? <p className="dl" style={{ color: "var(--muted)" }}>None recorded.</p> : (
              <dl className="dl">
                {locations.map(function (l, i) {
                  return (
                    <React.Fragment key={i}>
                      <dt>{l.address || "Location " + (i + 1)}</dt>
                      <dd>
                        {[l.sf ? Portal.num(l.sf) + " SF" : null, l.current_rent, l.lease_type, l.lease_expiration ? "exp " + l.lease_expiration : null].filter(Boolean).join(" · ") || "—"}
                        {l.annual_sales_range ? <div style={{ fontSize: 12, color: "var(--muted)" }}>Sales: {l.annual_sales_range}</div> : null}
                      </dd>
                    </React.Fragment>
                  );
                })}
              </dl>
            )}
          </div>

          <div className="detail-card">
            <h3>References</h3>
            {references.length === 0 ? <p className="dl" style={{ color: "var(--muted)" }}>None recorded.</p> : (
              <dl className="dl">
                {references.map(function (r, i) {
                  return (
                    <React.Fragment key={i}>
                      <dt>{(r.ref_kind || "ref") + ""}</dt>
                      <dd>
                        <b>{r.company || "—"}</b>{r.contact_name ? " · " + r.contact_name : ""}
                        {(r.phone || r.email) ? <div style={{ fontSize: 12, color: "var(--muted)" }}>{[r.phone ? Portal.formatPhone(r.phone) : null, r.email].filter(Boolean).join(" · ")}</div> : null}
                      </dd>
                    </React.Fragment>
                  );
                })}
              </dl>
            )}
          </div>

          <div className="detail-card">
            <h3>Financials (self-reported)</h3>
            <dl className="dl">
              <dt>Annual revenue</dt><dd>{app.annual_revenue_range || "—"}</dd>
              <dt>Projected revenue</dt><dd>{app.annual_revenue_proj_range || "—"}</dd>
              <dt>Gross margin</dt><dd>{app.gross_margin_range || "—"}</dd>
              <dt>Cash reserves</dt><dd>{app.cash_reserves_range || "—"}</dd>
              <dt>Rent budget</dt><dd>{app.monthly_rent_budget_range || "—"}</dd>
              <dt>Build-out cost</dt><dd>{app.buildout_cost_range || "—"}</dd>
              <dt>Build-out finance</dt><dd>{app.buildout_finance_method || "—"}</dd>
            </dl>
          </div>

          <div className="detail-card">
            <h3>Disclosures</h3>
            <dl className="dl">
              {disclosures.map(function (d, i) {
                var yes = d.y === true;
                return (
                  <React.Fragment key={i}>
                    <dt>{d.k}</dt>
                    <dd>
                      <span style={yes ? { color: "var(--brick)", fontWeight: 700 } : null}>{adYN(d.y)}</span>
                      {yes && d.x ? <div style={{ fontSize: 13, color: "var(--brick-deep)", marginTop: 4 }}>{d.x}</div> : null}
                    </dd>
                  </React.Fragment>
                );
              })}
              <dt>Certified accurate</dt><dd>{adYN(app.certify_accuracy)}</dd>
            </dl>
          </div>

          <div className="detail-card">
            <h3>Documents</h3>
            {documents.length === 0 ? <p className="dl" style={{ color: "var(--muted)" }}>No documents uploaded.</p> : (
              <div className="action-stack" style={{ gap: 8 }}>
                {documents.map(function (d, i) { return <AdminDocRow key={d.id || i} doc={d} demo={demo} />; })}
              </div>
            )}
          </div>

          <div className="detail-card">
            <h3>Activity timeline</h3>
            {events.length === 0 ? <p className="dl" style={{ color: "var(--muted)" }}>No events.</p> : (
              <dl className="dl">
                {events.map(function (e, i) {
                  return (
                    <React.Fragment key={i}>
                      <dt>{adRelTime(e.created_at)}</dt>
                      <dd>{(e.event_type || "event").replace(/_/g, " ")}{e.step ? " · step " + e.step : ""}{e.field ? " · " + e.field : ""}</dd>
                    </React.Fragment>
                  );
                })}
              </dl>
            )}
          </div>
        </div>

        {/* RIGHT — action panel */}
        <div style={{ position: "sticky", top: 88 }}>
          <div className="detail-card">
            <h3>Status</h3>
            <span className={adStatusTag(app.status)} style={{ fontSize: 12, padding: "7px 14px" }}>{adStatusLabel(app.status)}</span>
            <div className="action-stack" style={{ marginTop: 18 }}>
              <button className="btn sm ghost" disabled={busy} onClick={onSendStage2Invite}><Icon name="arrow" size={14} /> Send Stage 2 invite</button>
              <button className="btn sm ghost" disabled={busy} onClick={onMarkReviewing}><Icon name="clock" size={14} /> Mark reviewing</button>
              <button className="btn sm ghost" disabled={busy} onClick={onRequestDocs}><Icon name="file" size={14} /> Request documents</button>
              <button className="btn sm" disabled={busy} onClick={onApprove}><Icon name="check" size={14} /> Approve</button>
              <button className="btn sm ghost" disabled={busy} onClick={onDecline}><Icon name="x" size={14} /> Decline</button>
              <button className="btn sm ghost" disabled={busy} onClick={onWithdraw}>Withdraw</button>
            </div>
          </div>

          <div className="detail-card">
            <h3>Admin notes</h3>
            <textarea className="field-textarea" placeholder="Add an internal note…" value={noteText}
              onChange={function (e) { setNoteText(e.target.value); }} style={{ marginBottom: 10 }} />
            <button className="btn sm block" onClick={addNote} disabled={!noteText.trim()}><Icon name="pen" size={14} /> Add note</button>
            {noteReviews.length > 0 && (
              <div style={{ marginTop: 16 }}>
                {noteReviews.map(function (r, i) {
                  return (
                    <div key={i} style={{ borderTop: "1px solid var(--rule-soft)", paddingTop: 10, marginTop: 10 }}>
                      <div style={{ fontFamily: "var(--sans)", fontSize: 14, color: "var(--ink)" }}>{r.note}</div>
                      <div style={{ fontSize: 11, color: "var(--muted)", marginTop: 4, fontFamily: "var(--mono)" }}>
                        {(r.admin_name || "Admin")} · {adRelTime(r.created_at)}
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </div>

          <div className="detail-card">
            <h3>Export</h3>
            <button className="btn sm block ghost" onClick={function () { window.print(); }}><Icon name="file" size={14} /> Download PDF packet</button>
          </div>
        </div>
      </div>
    </div>
  );
}

function AdminDocRow({ doc, demo }) {
  const [opening, setOpening] = useAd(false);
  const integration = doc.source && doc.source !== "upload";

  function view() {
    if (integration || !doc.storage_path) { window.alert("This source is linked via " + (doc.source || "an integration") + " — view it in the connected account."); return; }
    if (demo) { window.alert("DEMO — would open a signed URL for " + doc.filename); return; }
    setOpening(true);
    var sb = window.portalSupabase;
    sb.storage.from((window.PORTAL_BUCKETS && window.PORTAL_BUCKETS.docs) || "tenant-portal-docs").createSignedUrl(doc.storage_path, 300).then(function (r) {
      setOpening(false);
      if (r && r.data && r.data.signedUrl) window.open(r.data.signedUrl, "_blank", "noopener");
      else window.alert("Could not open this document.");
    }).catch(function () { setOpening(false); window.alert("Could not open this document."); });
  }

  return (
    <div style={{ display: "flex", alignItems: "center", justifyContent: "space-between", gap: 12, borderBottom: "1px solid var(--rule-soft)", paddingBottom: 8 }}>
      <div style={{ minWidth: 0 }}>
        <div style={{ fontFamily: "var(--sans)", fontSize: 14, color: "var(--ink)", overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
          <Icon name="file" size={13} /> {doc.filename || "(untitled)"}
        </div>
        <div style={{ fontSize: 11, color: "var(--muted)", fontFamily: "var(--mono)", letterSpacing: ".08em", textTransform: "uppercase" }}>
          {(doc.document_type || "doc").replace(/_/g, " ")}{adFileSize(doc.file_size_bytes) ? " · " + adFileSize(doc.file_size_bytes) : ""}
        </div>
      </div>
      {integration
        ? <span className="pill outline" style={{ fontSize: 9 }}>{doc.source}</span>
        : <button className="btn sm ghost" disabled={opening} onClick={view}>{opening ? "…" : "View"}</button>}
    </div>
  );
}

/* ============================================================
   View 3 — Admin users
   ============================================================ */
function AdminUsers({ demo, auth }) {
  const [rows, setRows] = useAd(null);
  const [fullName, setFullName] = useAd("");
  const [email, setEmail] = useAd("");
  const [touched, setTouched] = useAd(false);
  const [busy, setBusy] = useAd(false);
  const [msg, setMsg] = useAd(null);

  const canManage = demo || (auth && auth.isSuper);

  const load = useCAd(function () {
    if (demo) { setRows(adDemoAdmins()); return; }
    var sb = window.portalSupabase;
    sb.from("admin_users").select("*").order("created_at", { ascending: true })
      .then(function (r) { setRows((r && r.data) || []); });
  }, [demo]);

  useEAd(function () { load(); }, [load]);

  const emailErr = Portal.validators.email(email);
  const nameErr = Portal.validators.required(fullName);

  function invite() {
    setTouched(true);
    if (emailErr || nameErr) return;
    setBusy(true); setMsg(null);
    if (demo) {
      setRows(function (prev) { return (prev || []).concat([{ user_id: "new-" + Date.now(), full_name: fullName, email: email, role: "leasing", is_super_admin: false, active: true, _pending: true }]); });
      setMsg("DEMO — pending admin added. They'd finish setup via the magic-link email.");
      setFullName(""); setEmail(""); setTouched(false); setBusy(false);
      return;
    }
    var sb = window.portalSupabase;
    // sb.auth.admin is not available client-side; insert a pending row and send a magic link so they can finish setup.
    sb.from("admin_users").insert({ full_name: fullName, email: email, role: "leasing", active: true })
      .then(function (r) {
        if (r && r.error) { setBusy(false); setMsg(r.error.message || "Could not add admin"); return; }
        try { sb.functions.invoke("invite-admin", { body: { email: email, full_name: fullName } }).catch(function () {}); } catch (e) {}
        sb.auth.signInWithOtp({ email: email }).catch(function () {});
        setBusy(false); setMsg("Invite sent — " + fullName + " finishes setup via the magic-link email.");
        setFullName(""); setEmail(""); setTouched(false);
        load();
      });
  }

  function toggleActive(u) {
    if (!canManage) return;
    var next = !u.active;
    if (demo) {
      setRows(function (prev) { return prev.map(function (x) { return x.user_id === u.user_id ? Object.assign({}, x, { active: next }) : x; }); });
      return;
    }
    var sb = window.portalSupabase;
    sb.from("admin_users").update({ active: next }).eq("user_id", u.user_id).then(function () { load(); });
  }

  if (!rows) return <CenterLoad label="Loading admins" />;

  return (
    <div>
      <div className="eyebrow brick" style={{ marginBottom: 22 }}><Icon name="shield" size={14} /> Admin users</div>

      {!canManage && (
        <div className="status-tag status-info_requested" style={{ display: "inline-block", marginBottom: 18 }}>
          Read-only — only super-admins can manage admins
        </div>
      )}

      <table className="app-table" style={{ marginBottom: 28 }}>
        <thead>
          <tr><th>Name</th><th>Email</th><th>Role</th><th>Access</th><th>Status</th>{canManage && <th></th>}</tr>
        </thead>
        <tbody>
          {rows.map(function (u) {
            return (
              <tr key={u.user_id} style={{ cursor: "default" }}>
                <td><span className="ap-name">{u.full_name || "—"}</span></td>
                <td>{u.email || "—"}</td>
                <td>{u.role || "—"}</td>
                <td>{u.is_super_admin ? <span className="pill gold" style={{ fontSize: 9 }}>Super-admin</span> : <span className="pill outline" style={{ fontSize: 9 }}>Admin</span>}</td>
                <td>
                  {u._pending
                    ? <span className="status-tag status-info_requested">Pending</span>
                    : <span className={"status-tag " + (u.active ? "status-approved" : "status-withdrawn")}>{u.active ? "Active" : "Disabled"}</span>}
                </td>
                {canManage && (
                  <td>
                    <button className="btn sm ghost" disabled={u.is_super_admin && !demo} onClick={function () { toggleActive(u); }}>
                      {u.active ? "Disable" : "Enable"}
                    </button>
                  </td>
                )}
              </tr>
            );
          })}
        </tbody>
      </table>

      {canManage && (
        <div className="detail-card" style={{ maxWidth: 520 }}>
          <h3>Add admin</h3>
          <Field name="full_name" label="Full name" type="text" required
            value={fullName} error={nameErr} touched={touched}
            onChange={function (n, v) { setFullName(v); }} onBlur={function () { setTouched(true); }} />
          <Field name="email" label="Email" type="email" required
            value={email} error={emailErr} touched={touched}
            onChange={function (n, v) { setEmail(v); }} onBlur={function () { setTouched(true); }} />
          <button className="btn sm block" disabled={busy} onClick={invite}>
            {busy ? "Sending…" : "Send invite"} <Icon name="arrow" size={14} />
          </button>
          {msg && <div style={{ fontFamily: "var(--sans)", fontSize: 13, color: "var(--ink-2)", marginTop: 12 }}>{msg}</div>}
          <p style={{ fontFamily: "var(--sans)", fontSize: 12, color: "var(--muted)", marginTop: 12 }}>
            New admins are added as a pending row and finish setup through the magic-link sign-in email.
          </p>
        </div>
      )}
    </div>
  );
}
