// @design-system: checkout/StripePaymentElement
/**
 * StripePaymentElement - React island for Stripe payment confirmation.
 *
 * Wraps Stripe Elements + PaymentElement. On submit calls
 * stripe.confirmPayment which redirects to returnUrlPath on success.
 *
 * @example
 * <StripePaymentElement
 *   publishableKey="pk_test_..."
 *   clientSecret="pi_..._secret_..."
 *   purchaseId="uuid"
 *   returnUrlPath="/checkout/uuid/complete"
 * />
 */

'use client';

import { useEffect, useState } from 'react';
import { loadStripe, type Stripe } from '@stripe/stripe-js';
import { Elements, PaymentElement, useStripe, useElements } from '@stripe/react-stripe-js';
import { useT } from '@/lib/i18n/react';
import { Button } from '@/components/ui/primitives/Button';
import { captureCaught } from '@/lib/observability';
import { FALLBACK_PRIMARY, FALLBACK_BG, FALLBACK_TEXT } from '@/lib/theme-fallbacks';

// ─── Types ──────────────────────────────────────────────────────────────────

export interface StripePaymentElementProps {
  publishableKey: string;
  clientSecret: string;
  purchaseId: string;
  returnUrlPath: string;
}

// ─── CheckoutForm ────────────────────────────────────────────────────────────

interface CheckoutFormProps {
  returnUrlPath: string;
}

function CheckoutForm({ returnUrlPath }: CheckoutFormProps) {
  const t = useT('checkout');
  const stripe = useStripe();
  const elements = useElements();

  const [submitting, setSubmitting] = useState(false);
  const [errMsg, setErrMsg] = useState<string | null>(null);

  async function handleSubmit(e: React.SyntheticEvent<HTMLFormElement>) {
    e.preventDefault();
    if (!stripe || !elements) return;
    setSubmitting(true);
    setErrMsg(null);
    try {
      // redirect: 'if_required' — only redirect for redirect-based payment methods
      // (iDEAL, Sofort, etc.). For card payments, confirmPayment returns the result
      // synchronously: { error } on decline or { paymentIntent } on success.
      // Without this flag, Stripe may redirect even for declined cards, leaving the
      // error message unreachable in the browser's DOM.
      const { error, paymentIntent } = await stripe.confirmPayment({
        elements,
        confirmParams: {
          return_url: `${window.location.origin}${returnUrlPath}`,
        },
        redirect: 'if_required',
      });
      if (error) {
        setErrMsg(error.message ?? t('payment_failed'));
        setSubmitting(false);
      } else if (paymentIntent) {
        // Non-redirect success — navigate to complete page with required params.
        window.location.href = `${returnUrlPath}?payment_intent=${paymentIntent.id}&redirect_status=${paymentIntent.status}`;
      }
      // Redirect-based methods (iDEAL etc.) navigate automatically — no further action.
    } catch (err) {
      captureCaught(err, { scope: 'ui.checkout.StripePaymentElement', severity: 'warning' });
      setErrMsg(t('payment_failed'));
      setSubmitting(false);
    }
  }

  return (
    <form onSubmit={handleSubmit} className="flex flex-col gap-4">
      <PaymentElement />
      {errMsg && (
        <p role="alert" data-testid="stripe-payment-error" className="text-danger-600 text-sm">
          {errMsg}
        </p>
      )}
      <Button
        type="submit"
        variant="primary"
        disabled={!stripe || submitting}
        loading={submitting}
        aria-busy={submitting}
      >
        {submitting ? t('processing') : t('pay_now')}
      </Button>
    </form>
  );
}

// ─── StripePaymentElement (default export) ──────────────────────────────────

/**
 * Resolve a CSS custom property to its computed value.
 * Stripe Elements rejects `var(--token)` strings — it requires resolved hex/rgb/hsl values.
 * Called client-side only (stripe is loaded in useEffect).
 */
function resolveCssVar(prop: string, fallback: string): string {
  if (typeof document === 'undefined') return fallback;
  const value = getComputedStyle(document.documentElement).getPropertyValue(prop).trim();
  return value || fallback;
}

export default function StripePaymentElement({
  publishableKey,
  clientSecret,
  returnUrlPath,
}: StripePaymentElementProps) {
  const [stripe, setStripe] = useState<Stripe | null>(null);

  useEffect(() => {
    loadStripe(publishableKey)
      .then(setStripe)
      .catch((err) => {
        captureCaught(err, { scope: 'ui.checkout.StripePaymentElement.load', severity: 'error' });
      });
  }, [publishableKey]);

  if (!stripe) return null;

  return (
    <Elements
      stripe={stripe}
      options={{
        clientSecret,
        locale: 'he',
        appearance: {
          theme: 'stripe',
          variables: {
            // Resolve CSS custom properties — Stripe rejects var(--token) strings.
            colorPrimary: resolveCssVar('--color-primary', FALLBACK_PRIMARY),
            colorBackground: resolveCssVar('--color-bg', FALLBACK_BG),
            colorText: resolveCssVar('--color-text', FALLBACK_TEXT),
            fontFamily: resolveCssVar('--font-sans', 'system-ui, sans-serif'),
            borderRadius: resolveCssVar('--radius-md', '6px'),
          },
        },
      }}
    >
      <CheckoutForm returnUrlPath={returnUrlPath} />
    </Elements>
  );
}
