// ─────────────────────────────────────────────────────────────────────────────
// SHARED Stripe card field + demo note. Used by all four payment breakpoints.
//
//   <StripeCardField …>  → the real, PCI-compliant Stripe Payment Element,
//                          themed to match this design. Mounts only when a
//                          publishable key is set in stripe-config.js.
//   <StripeDemoNote …>   → the small "demo mode" line shown under the mock
//                          card field when NO key is set (template ships this
//                          way, so the checkout looks complete with no account).
//
// Live-payment flow (deferred PaymentIntent — no server call needed to RENDER):
//   1. Element mounts with just the publishable key + amount.
//   2. On "Buy", payment.jsx calls the confirm fn we register here.
//   3. That validates the element, asks /api/create-payment-intent for a
//      client secret (secret key stays server-side), then confirmPayment().
// ─────────────────────────────────────────────────────────────────────────────

// Subtle lock glyph reused by the notes below.
const StripeLockGlyph = ({ size = 13, color = '#91837a' }) =>
<svg width={size} height={size} viewBox="0 0 16 16" fill="none" style={{ flexShrink: 0 }}>
    <rect x="3" y="7" width="10" height="7" rx="1.6" stroke={color} strokeWidth="1.4" />
    <path d="M5.2 7V5.2a2.8 2.8 0 0 1 5.6 0V7" stroke={color} strokeWidth="1.4" strokeLinecap="round" />
  </svg>;

// The subtle note shown beneath the demo card field (no Stripe key set).
const StripeDemoNote = ({ fontSize = 14 }) =>
<div style={{ display: 'flex', alignItems: 'center', gap: 7, paddingLeft: 2 }}>
    <StripeLockGlyph size={Math.round(fontSize * 0.95)} color="#a99e94" />
    <span style={{ fontFamily: 'Inter', fontWeight: 500, fontSize, color: '#a99e94', letterSpacing: '-0.01em' }}>
      Demo mode — add your Stripe keys to accept real payments.
    </span>
  </div>;

// Shown if a key IS set but Stripe.js can't load (offline preview, bad key).
// Falls back gracefully so the page never looks broken.
const StripeUnavailableNote = ({ fontSize = 14, label = 'Card' }) =>
<div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
    <label style={{ fontFamily: 'Inter', fontWeight: 500, color: '#101010', letterSpacing: '-0.02em', fontSize }}>{label}</label>
    <div style={{
    background: '#fffbf9', border: '1px dashed #e3c9b6', borderRadius: 8,
    padding: fontSize >= 20 ? '20px 16px' : '15px 12px',
    display: 'flex', alignItems: 'center', gap: 8
  }}>
      <StripeLockGlyph size={Math.round(fontSize * 0.95)} color="#a99e94" />
      <span style={{ fontFamily: 'Inter', fontWeight: 500, fontSize: fontSize * 0.85, color: '#a99e94', letterSpacing: '-0.01em' }}>
        Secure payment field unavailable — check your Stripe key / connection.
      </span>
    </div>
  </div>;

// The real Stripe Payment Element.
const StripeCardField = ({ fontSize = 17, total = 0, billing = {}, error, registerConfirm, label = 'Card', productId }) => {
  const mountRef = React.useRef(null);
  const stripeRef = React.useRef(null);
  const productRef = React.useRef(productId);
  productRef.current = productId;
  const elementsRef = React.useRef(null);
  const billingRef = React.useRef(billing);
  const totalRef = React.useRef(total);
  billingRef.current = billing;
  totalRef.current = total;

  const [phase, setPhase] = React.useState('init'); // init | ready | error
  const cfg = window.STRIPE_CONFIG || {};

  // ── Mount the Payment Element once ──────────────────────────────────────
  React.useEffect(() => {
    let cancelled = false;
    if (!window.Stripe || !cfg.publishableKey) {setPhase('error');return;}

    let stripe;
    try {stripe = window.Stripe(cfg.publishableKey);}
    catch (e) {setPhase('error');return;}
    stripeRef.current = stripe;

    const elements = stripe.elements({
      mode: 'payment',
      amount: Math.max(50, Math.round((total || 1) * 100)),
      currency: cfg.currency || 'cad',
      appearance: window.buildStripeAppearance ? window.buildStripeAppearance({ fontSize }) : undefined,
      fonts: [{ cssSrc: 'https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap' }]
    });
    elementsRef.current = elements;

    const pe = elements.create('payment', {
      layout: { type: 'tabs', defaultCollapsed: false },
      fields: { billingDetails: { address: 'never' } } // we collect country/zip ourselves (for tax)
    });
    pe.on('ready', () => {if (!cancelled) setPhase('ready');});
    pe.on('loaderror', () => {if (!cancelled) setPhase('error');});
    try {pe.mount(mountRef.current);}
    catch (e) {setPhase('error');}

    return () => {cancelled = true;try {pe.unmount();} catch (e) {}};
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // ── Keep the charge amount in sync with the live (tax-adjusted) total ────
  React.useEffect(() => {
    const el = elementsRef.current;
    if (el && total) {try {el.update({ amount: Math.max(50, Math.round(total * 100)) });} catch (e) {}}
  }, [total]);

  // ── Register the confirm fn that payment.jsx's submit() calls ───────────
  React.useEffect(() => {
    if (!registerConfirm) return;
    registerConfirm(async () => {
      const stripe = stripeRef.current,elements = elementsRef.current;
      if (!stripe || !elements) return { error: { message: 'Payment form is still loading — try again in a moment.' } };

      // 1) Validate the Payment Element.
      const { error: submitErr } = await elements.submit();
      if (submitErr) return { error: submitErr };

      // 2) Create the PaymentIntent server-side (secret key never touches the browser).
      let clientSecret;
      try {
        const r = await fetch('/api/create-payment-intent', {
          method: 'POST',
          headers: { 'content-type': 'application/json' },
          body: JSON.stringify({
            amount: totalRef.current,
            currency: cfg.currency || 'cad',
            email: billingRef.current.email,
            product: productRef.current || undefined
          })
        });
        const data = await r.json();
        clientSecret = data.clientSecret;
        if (!clientSecret) throw new Error(data.error && data.error.message || 'Could not start the payment.');
      } catch (e) {
        return { error: { message: e.message || 'Network error — please try again.' } };
      }

      // 3) Confirm. redirect:'if_required' keeps card payments on-page; only
      //    methods that need a redirect (e.g. some wallets) will navigate away.
      const b = billingRef.current;
      const { error: confirmErr } = await stripe.confirmPayment({
        elements,
        clientSecret,
        confirmParams: {
          return_url: window.location.origin + window.location.pathname + '?paid=1',
          payment_method_data: {
            billing_details: {
              name: b.name || undefined,
              email: b.email || undefined,
              address: {
                country: window.iso2For && window.iso2For(b.country) || undefined,
                postal_code: b.zip || undefined
              }
            }
          }
        },
        redirect: 'if_required'
      });
      if (confirmErr) return { error: confirmErr };
      // The PaymentIntent id is the part of the client secret before "_secret".
      // The Thank-you page passes it to the Worker, which re-checks with Stripe
      // that this exact intent actually succeeded before minting a download token.
      const paymentIntentId = (clientSecret || '').split('_secret')[0] || null;
      return { ok: true, paymentIntentId };
    });
  });

  if (phase === 'error') return <StripeUnavailableNote fontSize={fontSize} label={label} />;

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
      <label style={{ fontFamily: 'Inter', fontWeight: 500, color: '#101010', letterSpacing: '-0.02em', fontSize }}>{label}</label>
      <div ref={mountRef} style={{ minHeight: 44 }} />
      {phase === 'init' &&
      <div style={{ fontFamily: 'Inter', fontWeight: 500, fontSize: fontSize * 0.72, color: '#a99e94', display: 'flex', alignItems: 'center', gap: 6 }}>
          <StripeLockGlyph size={Math.round(fontSize * 0.8)} color="#a99e94" />
          Loading secure payment field…
        </div>}
      {error && <div style={{ fontFamily: 'Inter', fontWeight: 500, fontSize: 13, color: '#d6553e', paddingLeft: 4 }}>{error}</div>}
    </div>);

};

// Reassurance line shown beneath the Buy button on every breakpoint
// (in both demo and live mode): "🔒 Payments are secure & encrypted"
// followed by a subtle "Powered by Stripe" attribution.
const SecurePaymentLine = ({ fontSize = 16 }) =>
<div style={{ display: 'flex', width: '100%', alignItems: 'center', justifyContent: 'center', gap: 6, flexWrap: 'wrap' }}>
    <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
      <StripeLockGlyph size={Math.round(fontSize * 1.05)} color="#91837a" />
      <span style={{ fontFamily: 'Inter', fontWeight: 500, fontSize, color: '#91837a', letterSpacing: '-0.01em' }}>
        Payments are secure &amp; encrypted
      </span>
    </span>
    <span style={{ width: 1, height: fontSize * 1.1, background: '#e0d4c8', flexShrink: 0 }} />
    <span style={{ fontFamily: 'Inter', fontWeight: 500, fontSize, color: '#91837a', letterSpacing: '-0.01em', whiteSpace: 'nowrap' }}>
      Powered by&nbsp;<strong style={{ fontWeight: 700, color: '#6f6259', letterSpacing: '-0.03em' }}>stripe</strong>
    </span>
  </div>;

Object.assign(window, { StripeCardField, StripeDemoNote, StripeUnavailableNote, StripeLockGlyph, SecurePaymentLine });