/* global React, Button, Icon, LoadingSpinner, PlanPicker, PlanLimitMeter, CofoundersCalInline, CofoundersCalBooked, COFOUNDERS_CAL_BOOKING_URL, apiFetch, formatDateTime, useApiResource, useAuth, usePlans, validateBrowserReturnPath, getPlanLimitState, workflowMinIntervalSeconds, isPublicBillingPeriod, publicBillingPeriodOrDefault */
const { useState: useStateBilling, useEffect: useEffectBilling, useRef: useRefBilling } = React;

// ARM-10: canonical single-select cancellation reasons. The order is the
// order shown to the user. Free-text "Something else" detail is captured
// separately so we can aggregate cleanly on `category` without parsing
// user-typed strings.
const CANCEL_REASON_OPTIONS = [
  { value: 'too_expensive', label: "It's too expensive" },
  { value: 'missing_feature', label: 'Missing a feature I need' },
  { value: 'switching_tool', label: "I'm switching to a different tool" },
  { value: 'not_using_enough', label: "I'm not using it enough" },
  { value: 'other', label: 'Something else' },
];

const PAUSE_OPTIONS = [
  { days: 30, label: 'Pause for 30 days' },
  { days: 60, label: 'Pause for 60 days' },
];

function CancelModalShell({ title, subtitle, step, totalSteps, onClose, children, footer, busy }) {
  const dialogRef = useRefBilling(null);
  // Mount-only effect. We read `busy` + `onClose` through refs so the
  // keydown listener + focus management only run once per modal open,
  // instead of tearing down on every render where the parent passes a
  // fresh function reference. (Greptile flagged the previous
  // `[busy, onClose]` dependency array as a re-focus / scroll-lock
  // churn source.)
  const busyRef = useRefBilling(busy);
  const onCloseRef = useRefBilling(onClose);
  useEffectBilling(() => {
    busyRef.current = busy;
    onCloseRef.current = onClose;
  }, [busy, onClose]);
  useEffectBilling(() => {
    function handleKey(event) {
      if (event.key === 'Escape' && !busyRef.current) onCloseRef.current?.();
    }
    document.addEventListener('keydown', handleKey);
    const previouslyFocused = document.activeElement;
    const focusFrame = window.requestAnimationFrame(() => {
      const focusable = dialogRef.current?.querySelector('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
      if (focusable instanceof HTMLElement) focusable.focus();
    });
    document.body.style.overflow = 'hidden';
    return () => {
      document.removeEventListener('keydown', handleKey);
      window.cancelAnimationFrame(focusFrame);
      document.body.style.overflow = '';
      if (previouslyFocused instanceof HTMLElement && previouslyFocused.isConnected) {
        previouslyFocused.focus();
      }
    };
  }, []);
  return (
    <div
      className="dialog-backdrop cancel-modal-backdrop"
      onMouseDown={(event) => {
        if (event.target === event.currentTarget && !busy) onClose?.();
      }}>
      <div
        ref={dialogRef}
        className="cancel-modal"
        role="dialog"
        aria-modal="true"
        aria-labelledby="cancel-modal-title">
        <header className="cancel-modal-header">
          <div className="cancel-modal-step">Step {step} of {totalSteps}</div>
          <h2 id="cancel-modal-title" className="cancel-modal-title">{title}</h2>
          {subtitle && <p className="cancel-modal-subtitle">{subtitle}</p>}
          <button
            type="button"
            className="cancel-modal-close"
            onClick={onClose}
            disabled={busy}
            aria-label="Close">
            <Icon name="x" size={14} />
          </button>
        </header>
        <div className="cancel-modal-body">{children}</div>
        {footer && <footer className="cancel-modal-footer">{footer}</footer>}
      </div>
    </div>
  );
}

function CancelReasonStep({ value, otherDetail, onSelect, onOtherDetailChange, onNext, onClose, busy }) {
  const canContinue = Boolean(value) && (value !== 'other' || otherDetail.trim().length > 0);
  return (
    <CancelModalShell
      title="Before you go, what changed?"
      subtitle="Pick the one that best describes why you're canceling — this stays between us and helps us know where we missed."
      step={1}
      totalSteps={4}
      onClose={onClose}
      busy={busy}
      footer={
        <>
          <Button variant="ghost" type="button" disabled={busy} onClick={onClose}>Keep subscription</Button>
          <Button variant="primary" type="button" disabled={!canContinue || busy} onClick={onNext}>
            Continue<Icon name="chevronRight" size={13} />
          </Button>
        </>
      }>
      <ul className="cancel-reason-list">
        {CANCEL_REASON_OPTIONS.map((option) => (
          <li key={option.value}>
            <label className={`cancel-reason-option${value === option.value ? ' is-selected' : ''}`}>
              <input
                type="radio"
                name="cancel-reason"
                value={option.value}
                checked={value === option.value}
                onChange={() => onSelect(option.value)} />
              <span>{option.label}</span>
            </label>
          </li>
        ))}
      </ul>
      {value === 'other' && (
        <label className="field cancel-reason-other">
          <span className="field-label">Tell us more</span>
          <textarea
            className="textarea"
            rows={3}
            value={otherDetail}
            placeholder="What were you hoping Armature would do?"
            maxLength={2000}
            onChange={(event) => onOtherDetailChange(event.target.value)} />
          <span className="field-help">Required — a sentence or two is plenty.</span>
        </label>
      )}
    </CancelModalShell>
  );
}

function CancelPauseStep({ pauseDays, onSelectPause, onNext, onSkip, onBack, busy }) {
  return (
    <CancelModalShell
      title="Pause instead?"
      subtitle="Hit pause for 30 or 60 days. Your workspace, monitors, and history stay exactly where you left them — and billing won't resume until you say so."
      step={2}
      totalSteps={4}
      onClose={onSkip}
      busy={busy}
      footer={
        <>
          <Button variant="ghost" type="button" disabled={busy} onClick={onBack}>
            <Icon name="chevronLeft" size={13} />Back
          </Button>
          <div className="cancel-modal-footer-right">
            <button
              type="button"
              className="cancel-modal-link"
              disabled={busy}
              onClick={onSkip}>
              No thanks, just cancel
            </button>
            <Button
              variant="primary"
              type="button"
              disabled={!pauseDays || busy}
              loading={busy}
              loadingLabel="Pausing..."
              onClick={onNext}>
              Pause my subscription
            </Button>
          </div>
        </>
      }>
      <div className="cancel-pause-options">
        {PAUSE_OPTIONS.map((option) => (
          <label
            key={option.days}
            className={`cancel-pause-option${pauseDays === option.days ? ' is-selected' : ''}`}>
            <input
              type="radio"
              name="pause-days"
              value={option.days}
              checked={pauseDays === option.days}
              onChange={() => onSelectPause(option.days)} />
            <div>
              <div className="cancel-pause-option-title">{option.label}</div>
              <div className="cancel-pause-option-sub">Billing resumes automatically in {option.days} days.</div>
            </div>
          </label>
        ))}
      </div>
    </CancelModalShell>
  );
}

function CancelTalkStep({ onSkip, onBooked, onBack, onClose, busy }) {
  const [showCal, setShowCal] = useStateBilling(false);
  const [booked, setBooked] = useStateBilling(false);

  function handleBooked() {
    setBooked(true);
    onBooked();
  }

  return (
    <CancelModalShell
      title="Talk to a founder first?"
      subtitle="Grab 15 minutes with one of the cofounders. Free, no pressure — most calls end with us fixing the thing that wasn't working."
      step={3}
      totalSteps={4}
      onClose={onClose}
      busy={busy}
      footer={
        <>
          <Button variant="ghost" type="button" disabled={busy} onClick={onBack}>
            <Icon name="chevronLeft" size={13} />Back
          </Button>
          <div className="cancel-modal-footer-right">
            {booked ? (
              <Button
                variant="primary"
                type="button"
                disabled={busy}
                loading={busy}
                loadingLabel="Canceling..."
                onClick={onSkip}>
                Continue with cancellation
              </Button>
            ) : (
              <>
                <button type="button" className="cancel-modal-link" disabled={busy} onClick={onSkip}>
                  Skip — cancel anyway
                </button>
                {!showCal && (
                  <Button variant="primary" type="button" disabled={busy} onClick={() => setShowCal(true)}>
                    <Icon name="calendar" size={13} />Pick a time
                  </Button>
                )}
              </>
            )}
          </div>
        </>
      }>
      {booked ? (
        typeof CofoundersCalBooked === 'function' ? (
          <CofoundersCalBooked onClose={onSkip} />
        ) : (
          <div className="cancel-cal-booked">
            <Icon name="check" size={20} />
            <p>You&apos;re booked. Check your inbox for the calendar invite.</p>
          </div>
        )
      ) : showCal && typeof CofoundersCalInline === 'function' ? (
        <CofoundersCalInline onBooked={handleBooked} onClose={() => setShowCal(false)} />
      ) : showCal ? (
        <div className="cancel-cal-fallback">
          <p>The inline calendar didn&apos;t load. Open it in a new tab:</p>
          <Button
            variant="secondary"
            type="button"
            onClick={() => window.open(typeof COFOUNDERS_CAL_BOOKING_URL === 'string' ? COFOUNDERS_CAL_BOOKING_URL : 'https://armature.cal.com/founders/onboarding', '_blank', 'noopener,noreferrer')}>
            <Icon name="calendar" size={13} />Open booking page
          </Button>
        </div>
      ) : (
        <div className="cancel-talk-pitch">
          <ul>
            <li>15-minute call with a founder, not a sales rep.</li>
            <li>If we can fix what&apos;s broken, we will — most of the time we can.</li>
            <li>If not, we&apos;ll help you migrate cleanly. No hard feelings.</li>
          </ul>
        </div>
      )}
    </CancelModalShell>
  );
}

function CancelConfirmationStep({ result, busy, onReactivate, onClose }) {
  const isPause = result?.mode === 'paused';
  const effectiveAt = isPause ? result?.pausedUntil : result?.currentPeriodEnd;
  return (
    <CancelModalShell
      title={isPause ? 'Your subscription is paused' : 'Your subscription is canceled'}
      subtitle={isPause
        ? 'Billing is paused. You can reactivate anytime — or just wait, and it will resume automatically.'
        : "You'll keep full access until the end of your current billing period. After that, your workspace will go read-only until you reactivate."}
      step={4}
      totalSteps={4}
      onClose={onClose}
      busy={busy}
      footer={
        <>
          <Button variant="ghost" type="button" disabled={busy} onClick={onClose}>Close</Button>
          <Button
            variant="primary"
            type="button"
            loading={busy}
            loadingLabel="Reactivating..."
            onClick={onReactivate}>
            {isPause ? 'Resume now' : 'Reactivate subscription'}
          </Button>
        </>
      }>
      <div className="cancel-confirmation">
        <Icon name="check" size={28} />
        <p className="cancel-confirmation-line">
          {isPause ? 'Paused until ' : 'Canceled until '}
          <strong>{formatDateTime(effectiveAt) || 'the end of your current billing period'}</strong>.
        </p>
        <p className="muted">
          We just sent a confirmation email with the details. If anything looks off, reply to that email and we&apos;ll sort it out.
        </p>
      </div>
    </CancelModalShell>
  );
}

function ReactivateBanner({ billing, busy, onReactivate }) {
  if (!billing) return null;
  const isPaused = billing.subscription_status === 'paused';
  const isCancelPending = billing.cancel_at_period_end === true;
  if (!isPaused && !isCancelPending) return null;
  const effectiveAt = isPaused ? billing.paused_until : billing.current_period_end;
  return (
    <div className={`reactivate-banner ${isPaused ? 'is-paused' : 'is-cancel-pending'}`}>
      <div className="reactivate-banner-icon" aria-hidden="true">
        <Icon name={isPaused ? 'clock' : 'alert'} size={18} />
      </div>
      <div className="reactivate-banner-copy">
        <div className="reactivate-banner-title">
          {isPaused ? 'Subscription paused' : 'Subscription is scheduled to cancel'}
        </div>
        <div className="reactivate-banner-sub">
          {isPaused
            ? <>Billing resumes on <strong>{formatDateTime(effectiveAt) || 'the scheduled date'}</strong>. Reactivate anytime to resume now.</>
            : <>Access ends on <strong>{formatDateTime(effectiveAt) || 'the end of the current period'}</strong>. Reactivate before then to keep everything running.</>}
        </div>
      </div>
      <Button
        variant="primary"
        loading={busy}
        loadingLabel="Reactivating..."
        onClick={onReactivate}>
        {isPaused ? 'Resume now' : 'Reactivate'}
      </Button>
    </div>
  );
}

function SettingsBillingPage({ navigate }) {
  const auth = useAuth();
  const summary = useApiResource('/api/billing/summary');
  const [message, setMessage] = useStateBilling('');
  const [busyAction, setBusyAction] = useStateBilling('');
  // 'idle' | 'reason' | 'pause' | 'talk' | 'confirmation' | 'refund'
  const [cancelStep, setCancelStep] = useStateBilling('idle');
  const [cancelInput, setCancelInput] = useStateBilling({
    reason_category: '',
    reason: '',
    accept_pause_offer: false,
    pause_days: null,
    scheduled_call: false,
  });
  const [cancelResult, setCancelResult] = useStateBilling(null);
  const [cancelRefundReason, setCancelRefundReason] = useStateBilling('');
  const [period, setPeriod] = useStateBilling('monthly');
  const [choosingPlan, setChoosingPlan] = useStateBilling('');
  const plans = usePlans(period);
  const billing = summary.data?.billing;
  const currentPlanId = billing?.current_plan || auth?.me?.organization?.currentPlan || '';
  const currentBillingPeriod = billing?.billing_period || auth?.me?.organization?.billingPeriod || '';
  const subscriptionStatus = billing?.subscription_status || auth?.me?.organization?.subscriptionStatus || 'unpaid';
  const canManageExistingSubscription = ['active', 'trialing', 'past_due'].includes(subscriptionStatus);
  const isPaused = subscriptionStatus === 'paused';
  const isCancelPending = billing?.cancel_at_period_end === true;
  const isRefundFlow = cancelStep === 'refund';

  if (auth?.me?.role !== 'owner') {
    return (
      <div className="card settings-card">
        <h2>Billing</h2>
        <p className="muted">Only the workspace owner can view billing.</p>
      </div>
    );
  }

  async function run(action, key) {
    setBusyAction(key);
    setMessage('');
    try {
      await action();
      await summary.reload();
    } catch (error) {
      setMessage(error.message);
    } finally {
      setBusyAction('');
    }
  }

  function settingsReturnPath() {
    const browserPath = window.location.pathname && window.location.pathname !== '/'
      ? `${window.location.pathname}${window.location.search || ''}`
      : '/settings/billing';
    const queryIndex = browserPath.indexOf('?');
    if (queryIndex >= 0) {
      const params = new URLSearchParams(browserPath.slice(queryIndex + 1));
      const nestedReturnTo = validateBrowserReturnPath(params.get('return_to'));
      if (nestedReturnTo) return nestedReturnTo;
    }
    const basePath = queryIndex >= 0 ? browserPath.slice(0, queryIndex) : browserPath;
    return validateBrowserReturnPath(basePath) || '/settings/billing';
  }

  async function choosePlan(planId, plan = null, options = {}) {
    if (auth?.me?.role !== 'owner') {
      setMessage('Only the workspace owner can choose a plan.');
      return;
    }
    if (plan?.contactSales) {
      window.openCustomPlanCta(plan);
      return;
    }
    setChoosingPlan(planId);
    setMessage('');
    try {
      const result = await apiFetch('/api/billing/checkout-session', {
        method: 'POST',
        body: JSON.stringify({
          plan_id: planId,
          billing_period: publicBillingPeriodOrDefault(period),
          return_to: settingsReturnPath(),
          is_demo_mode: options.isDemoMode === true,
        }),
      });
      window.trackAmplitudeEvent?.('Checkout Started', {
        plan_id: planId,
        billing_period: publicBillingPeriodOrDefault(period),
        source: options.isDemoMode === true ? 'demo' : 'billing_settings',
      });
      window.location.assign(result.url);
    } catch (error) {
      setMessage(error.message);
    } finally {
      setChoosingPlan('');
    }
  }

  async function openBillingPortal() {
    setBusyAction('portal');
    setMessage('');
    try {
      const result = await apiFetch('/api/billing/portal-session', {
        method: 'POST',
        body: JSON.stringify({ return_to: settingsReturnPath() }),
      });
      window.location.assign(result.url);
    } catch (error) {
      setMessage(error.message);
      setBusyAction('');
    }
  }

  function resetCancelFlow() {
    setCancelStep('idle');
    setCancelInput({
      reason_category: '',
      reason: '',
      accept_pause_offer: false,
      pause_days: null,
      scheduled_call: false,
    });
    setCancelResult(null);
  }

  function startCancelFlow() {
    setMessage('');
    resetCancelFlow();
    setCancelStep('reason');
  }

  function startRefundFlow() {
    setMessage('');
    setCancelRefundReason('');
    setCancelStep('refund');
  }

  // `overrides` lets click handlers force pause/skip state directly into
  // the POST without waiting for a queued setCancelInput to commit.
  // Before this, `onNext` in the pause step called setCancelInput +
  // submitCancel synchronously, so submitCancel captured the
  // pre-update cancelInput and the API received accept_pause_offer
  // false — Greptile flagged this as a P1 because every Pause click
  // silently fell through to cancel.
  async function submitCancel(overrides = {}) {
    const acceptPauseOffer = overrides.accept_pause_offer ?? cancelInput.accept_pause_offer;
    const pauseDays = overrides.pause_days ?? cancelInput.pause_days;
    const scheduledCall = overrides.scheduled_call ?? cancelInput.scheduled_call;
    const payload = {
      reason_category: cancelInput.reason_category || null,
      reason: cancelInput.reason || undefined,
      accept_pause_offer: Boolean(acceptPauseOffer),
      pause_days: acceptPauseOffer ? pauseDays : undefined,
      scheduled_call: Boolean(scheduledCall),
    };
    await run(async () => {
      const result = await apiFetch('/api/billing/cancel', {
        method: 'POST',
        body: JSON.stringify(payload),
      });
      // Mirror the legacy `Subscription Cancelled` Amplitude event that
      // lived on the old single-step flow (added on main in the
      // Amplitude wiring PR), now extended with the ARM-10 fields so
      // pause/cancel funnels can be charted together.
      window.trackAmplitudeEvent?.('Subscription Cancelled', {
        cancel_reason: payload.reason || null,
        cancel_reason_category: payload.reason_category,
        cancellation_type: payload.accept_pause_offer ? 'paused' : 'period_end',
        pause_days: payload.pause_days || null,
        scheduled_call: payload.scheduled_call,
      });
      setCancelResult(result);
      setCancelStep('confirmation');
    }, payload.accept_pause_offer ? 'pause' : 'cancel');
  }

  async function reactivateFromConfirmation() {
    await run(async () => {
      await apiFetch('/api/billing/reactivate', { method: 'POST', body: '{}' });
      resetCancelFlow();
      setMessage('Subscription reactivated.');
    }, 'reactivate');
  }

  async function reactivateFromBanner() {
    await run(async () => {
      await apiFetch('/api/billing/reactivate', { method: 'POST', body: '{}' });
      setMessage('Subscription reactivated.');
    }, 'reactivate');
  }

  async function refund() {
    await run(async () => {
      await apiFetch('/api/billing/refund', {
        method: 'POST',
        body: JSON.stringify({ reason: cancelRefundReason }),
      });
      window.trackAmplitudeEvent?.('Refund Requested', {
        cancel_reason: cancelRefundReason || null,
      });
      window.trackAmplitudeEvent?.('Subscription Cancelled', {
        cancel_reason: cancelRefundReason || null,
        cancellation_type: 'refund',
      });
      setCancelStep('idle');
      setMessage('Refund requested and subscription canceled.');
    }, 'refund');
  }

  function renderCancelModal() {
    if (cancelStep === 'idle' || cancelStep === 'refund') return null;
    if (cancelStep === 'reason') {
      return (
        <CancelReasonStep
          value={cancelInput.reason_category}
          otherDetail={cancelInput.reason}
          onSelect={(value) => setCancelInput((prev) => ({
            ...prev,
            reason_category: value,
            reason: value === 'other' ? prev.reason : '',
          }))}
          onOtherDetailChange={(text) => setCancelInput((prev) => ({ ...prev, reason: text }))}
          onNext={() => setCancelStep('pause')}
          onClose={resetCancelFlow}
          busy={Boolean(busyAction)} />
      );
    }
    if (cancelStep === 'pause') {
      return (
        <CancelPauseStep
          pauseDays={cancelInput.pause_days}
          onSelectPause={(days) => setCancelInput((prev) => ({ ...prev, pause_days: days }))}
          onNext={() => {
            // Pass the pause flag into submitCancel directly so the POST
            // doesn't depend on a not-yet-committed setCancelInput.
            setCancelInput((prev) => ({ ...prev, accept_pause_offer: true }));
            submitCancel({ accept_pause_offer: true, pause_days: cancelInput.pause_days });
          }}
          onSkip={() => {
            // Don't clear pause_days — keep the user's selection so
            // going Back from Talk lands them on their previously
            // chosen duration. Only flip the acceptance flag.
            setCancelInput((prev) => ({ ...prev, accept_pause_offer: false }));
            setCancelStep('talk');
          }}
          onBack={() => setCancelStep('reason')}
          busy={busyAction === 'pause'} />
      );
    }
    if (cancelStep === 'talk') {
      return (
        <CancelTalkStep
          onBooked={() => setCancelInput((prev) => ({ ...prev, scheduled_call: true }))}
          onSkip={() => submitCancel({ accept_pause_offer: false, scheduled_call: cancelInput.scheduled_call })}
          onBack={() => setCancelStep('pause')}
          onClose={resetCancelFlow}
          busy={busyAction === 'cancel'} />
      );
    }
    if (cancelStep === 'confirmation') {
      return (
        <CancelConfirmationStep
          result={cancelResult}
          busy={busyAction === 'reactivate'}
          onReactivate={reactivateFromConfirmation}
          onClose={resetCancelFlow} />
      );
    }
    return null;
  }

  return (
    <div className="card settings-card billing-settings">
      <div className="card-header billing-settings-header">
        <div>
          <div className="card-title">Billing</div>
          <div className="card-sub">Manage plan, payment status, refunds, and cancellation.</div>
        </div>
        <Button size="sm" onClick={() => summary.reload()}><Icon name="refresh" size={12} />Refresh</Button>
      </div>
      <div className="billing-settings-body">
        {summary.loading && !summary.data ? (
          <div className="code inline-loading"><LoadingSpinner size="sm" label="Loading billing" />Loading billing...</div>
        ) : (
          <div className="billing-summary-grid">
            <div><span className="field-label">Status</span><strong>{billing?.subscription_status || 'unpaid'}</strong></div>
            <div><span className="field-label">Plan</span><strong>{billing?.current_plan || 'No plan'}</strong></div>
            <div><span className="field-label">Period</span><strong>{billing?.billing_period || '-'}</strong></div>
            {billing?.refund_eligible_until && (
              <div><span className="field-label">Refund until</span><strong>{formatDateTime(billing.refund_eligible_until)}</strong></div>
            )}
          </div>
        )}
        <ReactivateBanner
          billing={billing}
          busy={busyAction === 'reactivate'}
          onReactivate={reactivateFromBanner} />
        <div className="billing-limits-section">
          <div>
            <div className="billing-limits-title">Plan limits</div>
            <div className="billing-limits-copy">Current usage caps and workflow frequency for this workspace.</div>
          </div>
          <div className="billing-limit-grid">
            <PlanLimitMeter label="MCP servers" state={getPlanLimitState(auth, 'mcpServers', 0)} />
            <PlanLimitMeter label="Tool monitors" state={getPlanLimitState(auth, 'toolMonitors', 0)} />
            <PlanLimitMeter label="Scheduled workflows" state={getPlanLimitState(auth, 'scheduledWorkflows', 0)} />
            <div className="plan-limit-meter">
              <span>Workflow frequency</span>
              <strong>{workflowMinIntervalSeconds(auth)}s minimum</strong>
            </div>
          </div>
        </div>
        {message && <div className="auth-message">{message}</div>}
        {canManageExistingSubscription && (
          <div className="billing-actions">
            <Button variant="primary" loading={busyAction === 'portal'} loadingLabel="Opening..." onClick={openBillingPortal}>
              <Icon name="creditCard" size={13} />Add payment method
            </Button>
          </div>
        )}
        <div className="billing-plan-picker">
          <div className="billing-plan-picker-head">
            <div>
              <div className="card-title">Choose a plan</div>
              <div className="card-sub">Subscribe or change plans without returning to onboarding.</div>
            </div>
          </div>
          <PlanPicker
            period={period}
            setPeriod={setPeriod}
            loading={plans.loading}
            plans={plans.plans}
            onChoose={choosePlan}
            choosingPlan={choosingPlan}
            currentPlanId={currentPlanId}
            currentBillingPeriod={currentBillingPeriod}
          />
          {plans.error && <div className="auth-message">{plans.error.message}</div>}
        </div>
        <div className="billing-actions">
          {canManageExistingSubscription && billing?.refund_available && (
            <Button variant="danger" loading={busyAction === 'refund'} loadingLabel="Refunding..." onClick={startRefundFlow}>
              Get a refund
            </Button>
          )}
          {canManageExistingSubscription && !isPaused && !isCancelPending && (
            <Button onClick={startCancelFlow}>Cancel subscription</Button>
          )}
        </div>
        {isRefundFlow && (
          <div className="cancel-flow refund-flow">
            <div className="cancel-flow-header">
              <span className="cancel-flow-icon"><Icon name="creditCard" size={16} /></span>
              <div>
                <div className="cancel-flow-title-row">
                  <h3>Refund and cancel subscription</h3>
                  <span className="badge badge-fail"><span className="dot"></span>Refund path</span>
                </div>
                <p>Refund the latest eligible charge and cancel the subscription immediately. This is final.</p>
              </div>
            </div>
            <div className="cancel-flow-meta">
              <div><span className="field-label">Status</span><strong>{billing?.subscription_status || 'unpaid'}</strong></div>
              <div><span className="field-label">Refund until</span><strong>{formatDateTime(billing?.refund_eligible_until)}</strong></div>
            </div>
            <label className="field cancel-flow-reason">
              <span className="field-label">What changed?</span>
              <textarea
                className="textarea cancel-flow-textarea"
                rows={4}
                placeholder="Tell us what made Armature a bad fit."
                value={cancelRefundReason}
                onChange={(event) => setCancelRefundReason(event.target.value)} />
              <span className="field-help">This is optional, but it helps us understand where the product missed.</span>
            </label>
            <div className="cancel-flow-actions">
              <div className="cancel-flow-secondary-actions">
                <Button variant="primary" disabled={Boolean(busyAction)} onClick={() => setCancelStep('idle')}>Keep subscription</Button>
                <Button
                  className="cancel-flow-danger-action"
                  variant="ghost"
                  loading={busyAction === 'refund'}
                  loadingLabel="Refunding..."
                  onClick={refund}>
                  Refund and cancel
                </Button>
              </div>
            </div>
          </div>
        )}
      </div>
      {renderCancelModal()}
    </div>
  );
}

function PricingPage({ navigate, queryString = '' }) {
  const params = new URLSearchParams(queryString || '');
  const requestedPeriod = params.get('billing');
  const [period, setPeriod] = useStateBilling(isPublicBillingPeriod(requestedPeriod) ? requestedPeriod : 'monthly');
  const initialDemoMode = params.get('demo') === '1';
  const { loading, plans, error } = usePlans(period);

  function choose(planId, plan = null, options = {}) {
    if (plan?.contactSales) {
      window.openCustomPlanCta(plan);
      return;
    }
    const signupParams = new URLSearchParams({
      plan: planId,
      billing: publicBillingPeriodOrDefault(period),
    });
    if (options.isDemoMode === true) {
      signupParams.set('demo', '1');
    }
    navigate(`/signup?${signupParams.toString()}`);
  }

  return (
    <div className="pricing-page">
      <div className="pricing-page-brand">
        <img src="/frontend/assets/armature-wordmark-dark.svg" alt="Armature" />
      </div>
      <div className="pricing-head">
        <span className="pricing-eyebrow">Pricing</span>
        <h1 className="pricing-title">Simple pricing. 7-day free trial.</h1>
        <p className="pricing-lede">Try free for 7 days. Credit card required. Cancel anytime.</p>
      </div>
      {error && <div className="auth-message">{error.message}</div>}
      <PlanPicker
        period={period}
        setPeriod={setPeriod}
        loading={loading}
        plans={plans}
        onChoose={choose}
        choosingPlan=""
        initialDemoMode={initialDemoMode}
      />
    </div>
  );
}

window.SettingsBillingPage = SettingsBillingPage;
window.PricingPage = PricingPage;
