// Reseller portal dashboard — Phase 0 shell.
//
// Shows the signed-in user's own company info + account manager, a real
// "My assets" table (serialized units currently assigned to this
// company — see GET /api/portal/assets), and placeholder cards for the
// remaining Phase 1+ features (deal registration, pricing schedules,
// order history, marketing downloads, support tickets) that aren't
// built yet. Every placeholder card here is intentionally inert until
// its backend/API exists — no fake data, no buttons that go nowhere
// silently.
//
// Renders its content inside <ResellerShell> (see reseller-shell.jsx) —
// the shell owns the persistent header (identity + sign out) and the
// top tab-strip nav, so this file only needs to supply its own unique
// body content, same pattern as every admin-*-page.jsx using AdminShell.

function ResellerPortalDashboard({ onNavigate }) {
  const [state, setState] = useState({ status: "loading", user: null, company: null, isSoloStaff: false });
  const [assets, setAssets] = useState({ status: "loading", items: [] });
  const [tickets, setTickets] = useState({ status: "loading", items: [] });
  const [assetSearch, setAssetSearch] = useState("");
  // Solo-staff "view as company" switcher — only ever populated when
  // /api/portal/me reports isSoloStaff true (see reseller-shell.jsx's
  // header dropdown + routes/portal.ts's loadResellerContext).
  const [companies, setCompanies] = useState([]);
  // Self-service device linking (see reseller-device-linking.jsx) —
  // which unit's modal is open (null = closed), and whether this
  // signed-in user is allowed to connect/sync/link (company_admin or
  // Solo staff viewing-as; a plain member sees the modal read-only).
  const [linkingUnit, setLinkingUnit] = useState(null);
  const [canManageDevices, setCanManageDevices] = useState(false);

  const loadAssets = (search) => {
    const params = new URLSearchParams();
    if (search) params.set("search", search);
    fetch(`/api/portal/assets?${params.toString()}`, { credentials: "same-origin" })
      .then((r) => (r.ok ? r.json() : { assets: [] }))
      .then((data) => setAssets({ status: "ready", items: data.assets || [] }))
      .catch(() => setAssets({ status: "ready", items: [] }));
  };

  const loadTickets = () => {
    fetch("/api/portal/tickets", { credentials: "same-origin" })
      .then((r) => (r.ok ? r.json() : { tickets: [] }))
      .then((data) => setTickets({ status: "ready", items: data.tickets || [] }))
      .catch(() => setTickets({ status: "ready", items: [] }));
  };

  // Re-fetches /api/portal/me (which re-resolves effectiveCompanyId
  // server-side) — called both on mount and after a successful company
  // switch. `cancelledRef`-style guard is unnecessary here since this is
  // also invoked from a direct user action (switch), not just mount.
  const loadMe = (onDone) => {
    fetch("/api/portal/me", { credentials: "same-origin" })
      .then(async (r) => {
        if (!r.ok) throw new Error("not signed in");
        return r.json();
      })
      .then((data) => {
        setState({ status: "ready", user: data.user, company: data.company, isSoloStaff: !!data.isSoloStaff });
        if (data.isSoloStaff) {
          fetch("/api/portal/companies", { credentials: "same-origin" })
            .then((r) => (r.ok ? r.json() : { companies: [] }))
            .then((d) => setCompanies(d.companies || []))
            .catch(() => setCompanies([]));
        }
        if (onDone) onDone();
      })
      .catch(() => {
        onNavigate("reseller-login");
      });
  };

  const handleSwitchCompany = (companyId) => {
    fetch("/api/portal/switch-company", {
      method: "POST", credentials: "same-origin",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ companyId }),
    })
      .then((r) => (r.ok ? r.json() : Promise.reject()))
      .then(() => {
        // Re-resolve /me (new company name/tier/account manager) then
        // refetch every company-scoped list so the whole dashboard
        // reflects the newly-selected company, not just the header.
        loadMe(() => {
          loadAssets(assetSearch);
          loadTickets();
        });
      })
      .catch(() => { /* switch failed silently — dashboard stays on current company */ });
  };

  useEffect(() => {
    loadMe();
    loadAssets("");
    loadTickets();
    // Read-only status check (any signed-in user may call this) just to
    // learn `canManage` up front, so the "Link devices" button doesn't
    // have to wait for the modal to open to know whether to render
    // itself as disabled for a plain member.
    fetch("/api/portal/device-connections", { credentials: "same-origin" })
      .then((r) => (r.ok ? r.json() : { canManage: false }))
      .then((data) => setCanManageDevices(!!data.canManage))
      .catch(() => setCanManageDevices(false));
  }, []); // eslint-disable-line react-hooks/exhaustive-deps -- mount-only

  // Debounce the search-driven refetch so we're not hammering the API on
  // every keystroke — 250ms feels responsive without being chatty.
  useEffect(() => {
    if (state.status !== "ready") return;
    const t = setTimeout(() => loadAssets(assetSearch), 250);
    return () => clearTimeout(t);
  }, [assetSearch]); // eslint-disable-line react-hooks/exhaustive-deps

  if (state.status === "loading") {
    return <section style={{ background: "var(--pt-bg)", minHeight: "calc(100vh - 88px)" }} />;
  }

  const { user, company, isSoloStaff } = state;

  return (
    <ResellerShell
      page="portal-dashboard" onNavigate={onNavigate}
      userName={user.name} companyName={company.name}
      isSoloStaff={isSoloStaff} companies={companies}
      currentCompanyId={company.id} onSwitchCompany={handleSwitchCompany}
      subtitle="Reseller portal"
      title={`Welcome, ${firstName(user.name)}.`}
    >
      <p style={{
        fontFamily: "var(--font-body)", fontSize: 15,
        color: "var(--pt-fg-dim)", margin: "-16px 0 40px",
      }}>
        {company.name} · <TierBadge tier={company.tier} />
      </p>

      {/* Account manager card */}
        <div style={{
          background: "var(--pt-surface-2)",
          border: "1px solid var(--pt-border-3)",
          padding: "28px 30px", marginBottom: 40,
          display: "flex", flexWrap: "wrap", gap: 24, justifyContent: "space-between", alignItems: "flex-start",
        }}>
          <div style={{ display: "flex", gap: 18, alignItems: "flex-start" }}>
            <div style={{
              width: 40, height: 40, flexShrink: 0, display: "flex", alignItems: "center", justifyContent: "center",
              border: "1px solid var(--pt-border-subtle)", color: "var(--pt-fg-3)",
            }}><IconCustomers size={19} /></div>
            <div>
            <div style={{
              fontFamily: "var(--font-body)", fontSize: 10,
              letterSpacing: "0.28em", textTransform: "uppercase",
              color: "var(--pt-fg-dimmer)", fontWeight: 500, marginBottom: 10,
            }}>Your account manager</div>
            {company.account_manager_name ? (
              <>
                <div style={{
                  fontFamily: "var(--font-display)", fontWeight: 700,
                  fontSize: 20, textTransform: "uppercase", color: "var(--pt-fg)",
                }}>{company.account_manager_name}</div>
                <div style={{
                  fontFamily: "var(--font-body)", fontSize: 14,
                  color: "var(--pt-fg-dim)", marginTop: 6, lineHeight: 1.6,
                }}>
                  {company.account_manager_email && <div>{company.account_manager_email}</div>}
                  {company.account_manager_phone && <div>{company.account_manager_phone}</div>}
                </div>
              </>
            ) : (
              <div style={{
                fontFamily: "var(--font-body)", fontSize: 14,
                color: "var(--pt-fg-dimmer)",
              }}>Not yet assigned — your account manager will be in touch shortly.</div>
            )}
            </div>
          </div>
        </div>

        {/* My assets */}
        <div style={{
          display: "flex", alignItems: "center", justifyContent: "space-between",
          flexWrap: "wrap", gap: 14, marginBottom: 20,
        }}>
          <div style={{
            fontFamily: "var(--font-body)", fontSize: 10,
            letterSpacing: "0.28em", textTransform: "uppercase",
            color: "var(--pt-fg-dimmer)", fontWeight: 500,
          }}>My assets{assets.status === "ready" && ` (${assets.items.length})`}</div>
          <input
            value={assetSearch}
            onChange={(e) => setAssetSearch(e.target.value)}
            placeholder="Search by serial number or product…"
            data-testid="my-assets-search-input"
            style={{
              width: 280, boxSizing: "border-box",
              background: "var(--pt-surface-2)", border: "1px solid var(--pt-border-strong)",
              color: "var(--pt-fg)", fontFamily: "var(--font-body)",
              fontSize: 13.5, padding: "9px 12px", outline: "none",
            }}
          />
        </div>
        <div style={{
          background: "var(--pt-surface)",
          border: "1px solid var(--pt-border)",
          marginBottom: 44,
        }}>
          {assets.status === "loading" ? (
            <div style={{ padding: "22px 24px", fontFamily: "var(--font-body)", fontSize: 13.5, color: "var(--pt-fg-faint2)" }}>
              Loading…
            </div>
          ) : assets.items.length === 0 ? (
            <div style={{ padding: "22px 24px", fontFamily: "var(--font-body)", fontSize: 13.5, color: "var(--pt-fg-dimmer)" }}>
              {assetSearch
                ? "No assets match that search."
                : "No hardware has been assigned to your account yet. Your account manager will be in touch once units are allocated."}
            </div>
          ) : (
            <div style={{ overflowX: "auto" }}>
              <table style={{ width: "100%", borderCollapse: "collapse", fontFamily: "var(--font-body)" }}>
                <thead>
                  <tr style={{ borderBottom: "1px solid var(--pt-border-2)" }}>
                    <AssetTh>Product</AssetTh>
                    <AssetTh>Serial number</AssetTh>
                    <AssetTh>Assigned to</AssetTh>
                    <AssetTh>Location</AssetTh>
                    <AssetTh>Since</AssetTh>
                    <AssetTh>&nbsp;</AssetTh>
                    <AssetTh>&nbsp;</AssetTh>
                  </tr>
                </thead>
                <tbody>
                  {assets.items.map((a) => {
                    const disabled = !a.management_access_enabled;
                    return (
                      <tr
                        key={a.id} data-testid={`my-asset-row-${a.id}`}
                        onClick={() => { if (!disabled) onNavigate("unit-management", { unitId: a.id }); }}
                        style={{
                          borderBottom: "1px solid var(--pt-surface-3)",
                          cursor: disabled ? "default" : "pointer",
                          opacity: disabled ? 0.55 : 1,
                        }}
                        onMouseEnter={(e) => { if (!disabled) e.currentTarget.style.background = "var(--pt-surface-2)"; }}
                        onMouseLeave={(e) => { e.currentTarget.style.background = "transparent"; }}
                      >
                        <AssetTd>{a.product_name}</AssetTd>
                        <AssetTd mono>{a.serial_number}</AssetTd>
                        <AssetTd>{a.assigned_to_name || <span style={{ color: "var(--pt-fg-faint2)" }}>Company-wide</span>}</AssetTd>
                        <AssetTd>{[a.country, a.region].filter(Boolean).join(", ") || <span style={{ color: "var(--pt-fg-faint2)" }}>\u2014</span>}</AssetTd>
                        <AssetTd>{(a.updated_at || "").slice(0, 10)}</AssetTd>
                        <AssetTd>
                          {disabled ? (
                            <span style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--pt-warn-text)" }}>Access disabled</span>
                          ) : (
                            <span style={{ fontSize: 11, textTransform: "uppercase", letterSpacing: "0.06em", color: "var(--pt-fg-dimmer)" }}>Manage &rarr;</span>
                          )}
                        </AssetTd>
                        <AssetTd>
                          <button
                            type="button"
                            data-testid={`link-devices-${a.id}`}
                            onClick={(e) => { e.stopPropagation(); setLinkingUnit(a); }}
                            style={{
                              background: "none", border: "1px solid var(--pt-border-strong)",
                              color: "var(--pt-fg-3)", cursor: "pointer", padding: "6px 12px",
                              fontFamily: "var(--font-body)", fontSize: 10.5, fontWeight: 500,
                              letterSpacing: "0.08em", textTransform: "uppercase",
                            }}
                          >Link devices</button>
                        </AssetTd>
                      </tr>
                    );
                  })}
                </tbody>
              </table>
            </div>
          )}
        </div>

        {/* Phase 1+ feature placeholders */}
        <div style={{
          fontFamily: "var(--font-body)", fontSize: 10,
          letterSpacing: "0.28em", textTransform: "uppercase",
          color: "var(--pt-fg-dimmer)", fontWeight: 500, marginBottom: 20,
        }}>Coming to your portal</div>
        <div style={{
          display: "grid", gap: 18,
          gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))",
        }}>
          <ComingSoonCard Icon={IconApprovals} title="Deal registration" note="Register and track new opportunities." />
          <LiveFeatureCard
            Icon={IconQuote}
            title="Quotes" testId="portal-quotes-link"
            note="Build a quote from your priced catalogue and track its status."
            onClick={() => onNavigate("portal-quotes")}
          />
          <ComingSoonCard Icon={IconOrders} title="Order history" note="Track every order from placement to delivery." />
          <ComingSoonCard Icon={IconSpecSheets} title="Marketing downloads" note="Approved assets, spec sheets and brand materials." />
        </div>

        {/* Support — live, not a placeholder. Support ticket raising AND
            tracking lives exclusively in the portal now (removed from
            the public site) — resellers raise tickets here and see
            Solo staff replies here too (see support-page.jsx). */}
        <div style={{
          fontFamily: "var(--font-body)", fontSize: 10,
          letterSpacing: "0.28em", textTransform: "uppercase",
          color: "var(--pt-fg-dimmer)", fontWeight: 500,
          marginTop: 40, marginBottom: 20,
        }}>Support</div>
        <div style={{ display: "grid", gap: 14, gridTemplateColumns: "repeat(auto-fit, minmax(240px, 1fr))" }}>
          <LiveFeatureCard
            Icon={IconTicket} testId="portal-support-link" bare
            title="Raise a ticket"
            note="Raise a support ticket with the Solo team"
            onClick={() => onNavigate("support", { tab: "raise" })}
          />
          <LiveFeatureCard
            Icon={IconTicketList} testId="portal-my-tickets-link" bare
            title={`My tickets${tickets.status === "ready" ? ` (${tickets.items.length})` : ""}`}
            note={
              tickets.status === "ready" && tickets.items.filter((t) => t.status !== "closed" && t.status !== "resolved").length > 0
                ? `${tickets.items.filter((t) => t.status !== "closed" && t.status !== "resolved").length} open · view status & replies`
                : "View status & Solo team replies"
            }
            onClick={() => onNavigate("support", { tab: "my-tickets" })}
          />
        </div>

      {linkingUnit && (
        <ResellerDeviceLinkingModal
          unit={linkingUnit}
          canManage={canManageDevices}
          onCancel={() => setLinkingUnit(null)}
          onChanged={() => loadAssets(assetSearch)}
        />
      )}
    </ResellerShell>
  );
}

function AssetTh({ children }) {
  return (
    <th style={{
      textAlign: "left", padding: "14px 18px",
      fontFamily: "var(--font-body)", fontSize: 10.5,
      letterSpacing: "0.16em", textTransform: "uppercase",
      color: "var(--pt-fg-faint)", fontWeight: 500,
    }}>{children}</th>
  );
}

function AssetTd({ children, mono }) {
  return (
    <td style={{
      padding: "14px 18px",
      fontFamily: mono ? "monospace" : "var(--font-body)",
      fontSize: 13.5, color: "var(--pt-fg-2)",
    }}>{children}</td>
  );
}

// Inert placeholder card for a Phase 1+ feature that isn't built yet —
// no click handler, dimmed icon, "Coming soon" eyebrow. Shares the same
// footprint/hover-lift language as LiveFeatureCard so the grid reads as
// one consistent family, just visually "asleep".
function ComingSoonCard({ Icon, title, note }) {
  const [hover, setHover] = useState(false);
  return (
    <div
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        background: "var(--pt-surface)",
        border: `1px solid ${hover ? "var(--pt-border-subtle)" : "var(--pt-border)"}`,
        padding: "22px 22px 24px", transition: "border-color 160ms, transform 160ms",
        transform: hover ? "translateY(-2px)" : "translateY(0)",
      }}
    >
      <div style={{
        width: 34, height: 34, marginBottom: 16, display: "flex", alignItems: "center", justifyContent: "center",
        border: "1px solid var(--pt-border-3)", color: "var(--pt-fg-faint2)",
      }}>{Icon && <Icon size={17} />}</div>
      <div style={{
        fontFamily: "var(--font-body)", fontSize: 9,
        letterSpacing: "0.2em", textTransform: "uppercase",
        color: "var(--pt-fg-faint2)", marginBottom: 10, fontWeight: 500,
      }}>Coming soon</div>
      <div style={{
        fontFamily: "var(--font-display)", fontWeight: 700,
        fontSize: 16, textTransform: "uppercase", color: "var(--pt-fg-2)",
        marginBottom: 8,
      }}>{title}</div>
      <div style={{
        fontFamily: "var(--font-body)", fontSize: 13.5,
        color: "var(--pt-fg-dimmer)", lineHeight: 1.5,
      }}>{note}</div>
    </div>
  );
}

// Same card footprint as ComingSoonCard, but for a feature that's
// actually live — clicking it navigates straight to the real page
// instead of just sitting there inert. Used for the "Quotes" card
// (which replaced the old "Pricing schedules" placeholder once the
// reseller quote-builder shipped) and the two Support cards below —
// `bare` variant drops the "Live" eyebrow for those, since a support
// action isn't a "feature launch" the way Quotes was framed.
// Hover: icon box inverts to solid white/black, whole card lifts 2px
// and the border brightens — small, quick, and gives every clickable
// card in the portal the same tactile feel as the sidebar nav rows.
function LiveFeatureCard({ Icon, title, note, onClick, testId, bare }) {
  const [hover, setHover] = useState(false);
  return (
    <button
      type="button" onClick={onClick} data-testid={testId}
      onMouseEnter={() => setHover(true)} onMouseLeave={() => setHover(false)}
      style={{
        display: "block", width: "100%", textAlign: "left",
        background: "var(--pt-surface)",
        border: `1px solid ${hover ? "var(--pt-border-strong)" : "var(--pt-border-subtle)"}`,
        padding: "22px 22px 24px", cursor: "pointer",
        transition: "border-color 160ms, transform 160ms",
        transform: hover ? "translateY(-2px)" : "translateY(0)",
      }}
    >
      <div style={{
        width: 34, height: 34, marginBottom: 16, display: "flex", alignItems: "center", justifyContent: "center",
        border: "1px solid var(--pt-fg)", background: hover ? "var(--pt-fg)" : "transparent",
        color: hover ? "var(--pt-bg)" : "var(--pt-fg)", transition: "background 160ms, color 160ms",
      }}>{Icon && <Icon size={17} />}</div>
      {!bare && (
        <div style={{
          fontFamily: "var(--font-body)", fontSize: 9,
          letterSpacing: "0.2em", textTransform: "uppercase",
          color: "var(--pt-fg-dimmer)", marginBottom: 10, fontWeight: 500,
          display: "flex", alignItems: "center", gap: 7,
        }}><IconPulse size={6} />Live</div>
      )}
      <div style={{
        fontFamily: "var(--font-display)", fontWeight: 700,
        fontSize: 16, textTransform: "uppercase", color: "var(--pt-fg)",
        marginBottom: 8, marginTop: bare ? 0 : undefined,
      }}>{title}</div>
      <div style={{
        fontFamily: "var(--font-body)", fontSize: 13.5,
        color: "var(--pt-fg-dim)", lineHeight: 1.5,
        display: "flex", alignItems: "center", gap: 6,
      }}>{note} <IconChevronRight size={11} style={{ transform: hover ? "translateX(3px)" : "translateX(0)", transition: "transform 160ms" }} /></div>
    </button>
  );
}

function TierBadge({ tier }) {
  const label = tier === "gold" ? "Gold partner"
    : tier === "platinum" ? "Platinum partner"
    : tier === "regional_reseller" ? "Regional Reseller"
    : "Pending tier";
  return <span style={{ textTransform: "uppercase", letterSpacing: "0.05em" }}>{label}</span>;
}

function firstName(fullName) {
  return (fullName || "").trim().split(/\s+/)[0] || "there";
}

Object.assign(window, { ResellerPortalDashboard });
