/* Evolve Edge — Credits (the in-app billing page, route /upgrade).
   ----------------------------------------------------------------------------
   pitchiq#286 — CONSUMPTION ONLY. Marcos, 2026-09-22 (binding): there are no
   subscriptions, plans or tiers in any Evolve product, and credits come only
   from the platform. This page used to be "Plans & billing" — a plan catalog
   (Scout "$0 free forever", Deployments "Talk to sales"), a "Your plan"
   snapshot and a monthly-allowance meter. All of that is gone. What remains is
   the balance and the one place credits are bought: Evolve Suite.

   THE ROUTE STAYS, under its old name, because two things still land here:
     • old links and bookmarks to /app#/upgrade, and
     • the sidebar's "Add credits" when no Suite page can be built (nav.jsx
       `onOpenBilling`: no SUITE_URL, or an unknown workspace kind).
   It sells nothing.

   React-via-Babel: components are globals (no imports/bundler), so every JSX
   file shares ONE global scope — helper names here are page-specific on
   purpose. CSS lives in app/upgrade.css. */

/** The "expiring soon" window, in days — the same 30 the dashboard's nudge uses. */
const CREDIT_EXPIRY_WARNING_DAYS = 30;
const MS_PER_DAY = 24 * 60 * 60 * 1000;

/** Whole days until a credit lot expires, rounded up and never negative; null when unparseable. */
function creditLotDaysLeft(atIso) {
  const ms = new Date(atIso).getTime() - Date.now();
  if (isNaN(ms)) return null;
  return Math.max(0, Math.ceil(ms / MS_PER_DAY));
}

// ============================================================================
// Credit snapshot — this workspace's credit pool, and when its nearest credits expire.
// Read off the store (hydrated from /me). NOT the dashboard's figure since #315: Home shows what the
// member can spend under any monthly limit (/api/shell `compactAvailability`); this is the pool.
// ============================================================================
function CreditSnapshot() {
  const balance = MP.packBalance();              // platform-reported, or null = unknown (§1.3)
  const exp = MP.soonestExpiry();                // { atIso, briefs } | null
  const hasExpiring = !!(exp && exp.briefs > 0);
  const daysLeft = hasExpiring ? creditLotDaysLeft(exp.atIso) : null;
  const soon = hasExpiring && MP.expiringSoon(CREDIT_EXPIRY_WARNING_DAYS);

  return (
    <div className="pi-up-snapshot mp-fade">
      <div className="pi-up-snap pi-up-snap--accent">
        <span className="pi-up-snap__label"><Icon name="Database" size={13} /> Brief credits</span>
        {balance != null ? (
          <>
            <span className="pi-up-snap__value pi-up-num">{balance}</span>
            <span className="pi-up-snap__sub">Prepaid credits, burned oldest-first</span>
          </>
        ) : (
          <>
            <span className="pi-up-snap__value">{CREDITS_UNKNOWN.value}</span>
            <span className="pi-up-snap__sub">{CREDITS_UNKNOWN.text}</span>
          </>
        )}
      </div>
      <div className="pi-up-snap">
        <span className="pi-up-snap__label"><Icon name="CalendarClock" size={13} /> Next expiry</span>
        {hasExpiring ? (
          <>
            <span className="pi-up-snap__value pi-up-num" style={{ fontSize: 18 }}>{fmtExpiryDate(exp.atIso)}</span>
            <span className={"pi-up-snap__sub" + (soon ? " is-warn" : "")}>
              {exp.briefs} {exp.briefs === 1 ? "credit" : "credits"} · {soon ? `expiring in ${daysLeft}d` : "good for 12 months"}
            </span>
          </>
        ) : (
          <>
            <span className="pi-up-snap__value" style={{ fontSize: 18 }}>—</span>
            <span className="pi-up-snap__sub">No expiring credits</span>
          </>
        )}
      </div>
    </div>
  );
}

// ============================================================================
// "Buy more briefs" — Edge sells nothing; this links out to the Suite.
// ============================================================================
// #269 — the destination comes from nav.jsx's `suiteAddCreditsHref`, the same resolver the
// sidebar uses: the Suite page for the pot of the workspace the user is IN. This card used to
// send everyone to the ACCOUNT page, so a team's purchase aimed at the personal pot.
//
// The button shows only to someone who can buy, by the shell's own rule (`canManageBilling`,
// which the sidebar's button follows). Spec `3XDQoF0G2E` rev 20 L129-L132: a team App Manager
// or Member cannot buy and does not see "Add credits". They get one line instead, as on Coach
// (matchiq-for-sellers `REQUEST_CREDITS_MESSAGE`).
//
// No button either when no correct page exists (no SUITE_URL, an unknown workspace kind) or
// before the shell context has loaded — and no ask-an-admin line then, since nothing says the
// viewer cannot buy.
function BuyCreditsCard({ ctx }) {
  const shell = window.EvolveShell;
  const known = !!(ctx && shell);
  const canBuy = known && shell.canManageBilling(ctx.workspace, ctx.role);
  const href = canBuy ? suiteAddCreditsHref(ctx) : null;
  return (
    <Card className="mp-fade">
      <div className="mp-card__pad" style={{ textAlign: "center" }}>
        <h3 className="text-heading-3" style={{ margin: "0 0 6px" }}>Buy more briefs</h3>
        <p style={{ margin: "0 0 14px", color: "var(--fg-2)", fontSize: "var(--fs-body-2)" }}>
          Credits are bought once, for every Evolve app, in Evolve Suite.
        </p>
        {href
          ? <Button variant="primary" size="sm" icon="CreditCard"
              onClick={() => { window.location.href = href; }}>
              Add credits in Evolve Suite
            </Button>
          : known && !canBuy
            ? <p style={{ margin: 0, color: "var(--fg-2)" }}>Ask a workspace owner or admin to add credits in Evolve Suite.</p>
            : null}
      </div>
    </Card>
  );
}

// ============================================================================
// The page
// ============================================================================
function UpgradePage({ path }) {
  useStoreTick();
  // #315 — the answer this page's <Shell> loaded, not a second /api/shell read of its own (each one
  // reads the platform). A switch still clears it at once, so the card never shows the old pot (#269).
  const shellCtx = useCachedShellContext();

  // People come here to check their balance, so re-read it on arrival rather than trusting the
  // figure hydrate loaded (a purchase in the Suite, or a brief spent in another tab, moves it). A
  // failed read keeps the last known figure; the store's `mp-state` re-renders this page on success.
  React.useEffect(() => { MP.refreshMe().catch(() => {}); }, []);

  return (
    <Shell path={path} width="mp-w-3xl">
      <PageHeader
        title="Credits"
        eyebrow={<><Icon name="Zap" size={13} /> Evolve Edge</>}
        back={{ to: "/dashboard", label: "Back to home" }} />
      <CreditSnapshot />
      <BuyCreditsCard ctx={shellCtx} />
    </Shell>
  );
}

Object.assign(window, { UpgradePage, BuyCreditsCard, CreditSnapshot });
