'use client';

import { useCallback, useEffect, useMemo, useState } from 'react';
import { loadStripe } from '@stripe/stripe-js';
import { Elements, PaymentElement, useElements, useStripe } from '@stripe/react-stripe-js';
import { useT } from '@/lib/i18n/react';
import { fetchWithRefresh } from '@/lib/api/refresh-on-401';
import { captureCaught } from '@/lib/observability';
import { Button } from '@/components/ui/primitives/Button';
import { RadioGroup, RadioItem } from '@/components/ui/primitives/RadioGroup';
import { Spinner } from '@/components/ui/feedback/Spinner';
import { InlineNotice } from '@/components/ui/feedback/InlineNotice';
import { Icon } from '@/components/ui/icons/Icon';
import { formatPaymentMethodLabel } from '@/lib/format';

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

interface StoredPaymentMethod {
  id: string;
  brand: string;
  last4: string;
  isDefault: boolean;
}

export interface StoredPaymentMethodSelectorProps {
  selectedId: string | null;
  onSelect: (id: string) => void;
  csrfToken: string;
  purchaseId: string | null;
}

type PaymentMethodsResponse = {
  ok: boolean;
  methods?: StoredPaymentMethod[];
  error?: string;
};

type SetupIntentResponse = {
  ok: boolean;
  clientSecret?: string;
  error?: string;
};

type SaveMethodResponse = {
  ok: boolean;
  method?: StoredPaymentMethod;
  error?: string;
};

const HAS_STRIPE_ELEMENTS = true;

// ─── Setup form (inside Stripe Elements) ─────────────────────────────────────

interface CardSetupFormProps {
  csrfToken: string;
  purchaseId: string | null;
  onSuccess: (methodId: string) => void;
  onCancel: () => void;
}

function CardSetupForm({ csrfToken, purchaseId, onSuccess, onCancel }: CardSetupFormProps) {
  const t = useT('checkout_modal');
  const tSaved = useT('saved_cards');
  const tPurchase = useT('purchase_flow');
  const tCommon = useT('common');
  const stripe = useStripe();
  const elements = useElements();
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  async function handleSubmit(e: React.SyntheticEvent<HTMLFormElement>) {
    e.preventDefault();
    if (!stripe || !elements) return;
    setSaving(true);
    setError(null);

    const { error: confirmError, setupIntent } = await stripe.confirmSetup({
      elements,
      confirmParams: {
        return_url: purchaseId
          ? `${window.location.origin}/checkout/${purchaseId}/complete`
          : window.location.href,
      },
      redirect: 'if_required',
    });

    if (confirmError) {
      setError(confirmError.message ?? t('error_generic'));
      setSaving(false);
      return;
    }

    const pmId =
      typeof setupIntent?.payment_method === 'string' ? setupIntent.payment_method : null;

    if (!pmId) {
      setError(tPurchase('card_requires_auth'));
      setSaving(false);
      return;
    }

    try {
      const res = await fetchWithRefresh('/api/payment-methods', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-csrf-token': csrfToken,
        },
        body: JSON.stringify({ paymentMethodId: pmId }),
      });
      const data = (await res.json()) as SaveMethodResponse;
      if (!data.ok || !data.method) throw new Error(data.error ?? 'save failed');
      onSuccess(data.method.id);
    } catch (err) {
      captureCaught(err, {
        scope: 'features.checkout-modal.StoredPaymentMethodSelector.save',
        severity: 'warning',
      });
      setError(tSaved('setup_failed'));
      setSaving(false);
    }
  }

  return (
    <form onSubmit={(e) => void handleSubmit(e)} className="mt-4 flex flex-col gap-4">
      <PaymentElement />
      {error && <InlineNotice tone="danger" description={error} />}
      <div className="flex flex-col gap-2">
        <Button type="submit" variant="primary" size="lg" className="w-full" loading={saving}>
          {tSaved('save_card')}
        </Button>
        <Button
          type="button"
          variant="ghost"
          size="lg"
          className="w-full"
          onClick={onCancel}
          disabled={saving}
        >
          {tCommon('cancel')}
        </Button>
      </div>
    </form>
  );
}

// ─── Main selector ───────────────────────────────────────────────────────────

export function StoredPaymentMethodSelector({
  selectedId,
  onSelect,
  csrfToken,
  purchaseId,
}: StoredPaymentMethodSelectorProps) {
  const t = useT('checkout_modal');
  const [methods, setMethods] = useState<StoredPaymentMethod[]>([]);
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);
  const [showSetup, setShowSetup] = useState(false);
  const [setupLoading, setSetupLoading] = useState(false);
  const [clientSecret, setClientSecret] = useState<string | null>(null);
  const [setupError, setSetupError] = useState<string | null>(null);
  const [placeholderMessage, setPlaceholderMessage] = useState<string | null>(null);

  const publishableKey = import.meta.env.PUBLIC_STRIPE_PUBLISHABLE_KEY as string | undefined;
  const stripePromise = useMemo(
    () => (publishableKey ? loadStripe(publishableKey) : null),
    [publishableKey],
  );

  const pickDefaultId = useCallback((list: StoredPaymentMethod[]): string | null => {
    if (list.length === 0) return null;
    return (list.find((m) => m.isDefault) ?? list[0])?.id ?? null;
  }, []);

  const fetchMethods = useCallback(async (): Promise<StoredPaymentMethod[]> => {
    const res = await fetchWithRefresh('/api/payment-methods', {
      headers: { 'x-csrf-token': csrfToken },
    });
    const data = (await res.json()) as PaymentMethodsResponse;
    if (!data.ok || !data.methods) throw new Error(data.error ?? 'fetch failed');
    return data.methods;
  }, [csrfToken]);

  const applyMethods = useCallback(
    (list: StoredPaymentMethod[], autoSelect: boolean) => {
      setMethods(list);
      if (autoSelect) {
        const defaultId = pickDefaultId(list);
        if (defaultId) onSelect(defaultId);
      }
    },
    [onSelect, pickDefaultId],
  );

  useEffect(() => {
    let cancelled = false;
    void (async () => {
      try {
        const list = await fetchMethods();
        if (cancelled) return;
        applyMethods(list, true);
      } catch (err) {
        if (cancelled) return;
        captureCaught(err, {
          scope: 'features.checkout-modal.StoredPaymentMethodSelector.load',
          severity: 'warning',
        });
        setLoadError(t('error_generic'));
      } finally {
        if (!cancelled) setLoading(false);
      }
    })();
    return () => {
      cancelled = true;
    };
  }, [applyMethods, fetchMethods, t]);

  async function handleAddCard() {
    if (!HAS_STRIPE_ELEMENTS || !stripePromise) {
      setPlaceholderMessage('Card collection coming soon');
      return;
    }

    setSetupError(null);
    setPlaceholderMessage(null);
    setSetupLoading(true);

    try {
      const res = await fetchWithRefresh('/api/payment-methods/setup-intent', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'x-csrf-token': csrfToken,
        },
        body: '{}',
      });
      const data = (await res.json()) as SetupIntentResponse;
      if (!data.ok || !data.clientSecret) {
        throw new Error(data.error ?? 'setup-intent failed');
      }
      setClientSecret(data.clientSecret);
      setShowSetup(true);
    } catch (err) {
      captureCaught(err, {
        scope: 'features.checkout-modal.StoredPaymentMethodSelector.setup-intent',
        severity: 'warning',
      });
      setSetupError(t('error_generic'));
    } finally {
      setSetupLoading(false);
    }
  }

  async function handleSetupSuccess(methodId: string) {
    setShowSetup(false);
    setClientSecret(null);
    try {
      const list = await fetchMethods();
      applyMethods(list, false);
      const saved = list.find((m) => m.id === methodId);
      onSelect(saved?.id ?? pickDefaultId(list) ?? methodId);
    } catch (err) {
      captureCaught(err, {
        scope: 'features.checkout-modal.StoredPaymentMethodSelector.refetch',
        severity: 'warning',
      });
      onSelect(methodId);
    }
  }

  function handleSetupCancel() {
    setShowSetup(false);
    setClientSecret(null);
    setSetupError(null);
  }

  if (loading) {
    return (
      <div className="flex flex-col gap-4">
        <h2 id="stored-payment-section-title" className="text-text-primary text-base font-semibold">
          {t('saved_card_section_title')}
        </h2>
        <div className="flex justify-center py-4">
          <Spinner size="md" label={t('loading')} />
        </div>
      </div>
    );
  }

  return (
    <div className="flex flex-col gap-4">
      <h2 id="stored-payment-section-title" className="text-text-primary text-base font-semibold">
        {t('saved_card_section_title')}
      </h2>

      {loadError && <InlineNotice tone="danger" description={loadError} />}
      {setupError && <InlineNotice tone="danger" description={setupError} />}
      {placeholderMessage && <InlineNotice tone="info" description={placeholderMessage} />}

      {showSetup && clientSecret && stripePromise ? (
        <Elements stripe={stripePromise} options={{ clientSecret }}>
          <CardSetupForm
            csrfToken={csrfToken}
            purchaseId={purchaseId}
            onSuccess={(id) => void handleSetupSuccess(id)}
            onCancel={handleSetupCancel}
          />
        </Elements>
      ) : (
        <>
          {methods.length === 0 ? (
            <Button
              type="button"
              variant="secondary"
              size="lg"
              className="w-full"
              loading={setupLoading}
              onClick={() => void handleAddCard()}
            >
              {t('add_card_inline')}
            </Button>
          ) : (
            <>
              <RadioGroup
                value={selectedId ?? ''}
                onValueChange={onSelect}
                aria-labelledby="stored-payment-section-title"
              >
                {methods.map((method) => (
                  <RadioItem
                    key={method.id}
                    value={method.id}
                    id={`stored-payment-${method.id}`}
                    label={
                      <span className="flex items-center gap-3">
                        <Icon
                          name="CreditCard"
                          size="sm"
                          className="text-text-secondary shrink-0"
                        />
                        <span className="text-text-primary text-sm font-medium">
                          {formatPaymentMethodLabel(method.brand, method.last4)}
                        </span>
                      </span>
                    }
                  />
                ))}
              </RadioGroup>

              <Button
                type="button"
                variant="ghost"
                size="sm"
                className="text-text-link hover:text-text-link-hover h-auto self-start p-0 font-medium underline hover:bg-transparent"
                loading={setupLoading}
                onClick={() => void handleAddCard()}
              >
                {t('add_card_inline')}
              </Button>
            </>
          )}
        </>
      )}
    </div>
  );
}
