import React, { useEffect, useMemo, useRef, useState } from 'react';
import { Elements, CardElement, useElements, useStripe } from '@stripe/react-stripe-js';
import type { Stripe as StripeInstance } from '@stripe/stripe-js';
import { useTranslation } from 'react-i18next';
import { Button } from '@/components/ui/button';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Alert, AlertDescription } from '@/components/ui/alert';
import { Loader2 } from 'lucide-react';

 type StripePromise = Promise<StripeInstance | null>;

interface PaymentFormProps {
  packageId: number;
  packageName: string;
  price: number;
  currency?: string;
  stripePromise: StripePromise;
  paypalClientId?: string | null;
  onSuccess: () => void;
}

declare global {
  interface Window {
    paypal?: any;
  }
}

const formatCurrency = (value: number, currency = 'EUR') =>
  new Intl.NumberFormat('de-DE', {
    style: 'currency',
    currency,
  }).format(value);

const getCsrfToken = () =>
  (document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement | null)?.content ?? '';

async function postJson<T>(url: string, body: unknown, csrfToken: string): Promise<T> {
  const response = await fetch(url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'X-CSRF-TOKEN': csrfToken,
    },
    body: JSON.stringify(body),
  });

  if (response.status === 204) {
    return {} as T;
  }

  const data = await response.json().catch(() => ({}));

  if (!response.ok) {
    const message = (data as { message?: string; error?: string }).message ?? (data as { message?: string; error?: string }).error ?? 'Request failed.';
    throw new Error(message);
  }

  return data as T;
}

export default function PaymentForm({
  packageId,
  packageName,
  price,
  currency = 'EUR',
  stripePromise,
  paypalClientId,
  onSuccess,
}: PaymentFormProps) {
  const { t } = useTranslation('marketing');
  const csrfToken = useMemo(getCsrfToken, []);
  const [provider, setProvider] = useState<'stripe' | 'paypal'>('stripe');
  const [statusMessage, setStatusMessage] = useState<string | null>(null);
  const [errorMessage, setErrorMessage] = useState<string | null>(null);
  const [freeStatus, setFreeStatus] = useState<'idle' | 'loading' | 'done' | 'error'>('idle');

  useEffect(() => {
    setErrorMessage(null);
    setStatusMessage(null);
  }, [provider]);

  useEffect(() => {
    if (price === 0 && freeStatus === 'idle') {
      const assignFree = async () => {
        try {
          setFreeStatus('loading');
          await postJson<{ status: string }>('/purchase/free', { package_id: packageId }, csrfToken);
          setFreeStatus('done');
          setStatusMessage(
            t('payment.free_assigned', {
              defaultValue: 'Kostenloses Paket wurde zugewiesen.',
              package: packageName,
            })
          );
          onSuccess();
        } catch (error) {
          setFreeStatus('error');
          setErrorMessage((error as Error).message ?? 'Free package assignment failed.');
        }
      };

      assignFree();
    }
  }, [csrfToken, freeStatus, onSuccess, packageId, packageName, price, t]);

  if (price === 0) {
    return (
      <Card>
        <CardHeader>
          <CardTitle>{t('payment.title', { defaultValue: 'Zahlung' })}</CardTitle>
        </CardHeader>
        <CardContent className="space-y-4">
          {freeStatus === 'loading' && (
            <div className="flex items-center space-x-2 text-sm text-gray-600">
              <Loader2 className="h-4 w-4 animate-spin" />
              <span>{t('payment.processing_free', { defaultValue: 'Paket wird freigeschaltet �' })}</span>
            </div>
          )}
          {statusMessage && (
            <Alert variant="success">
              <AlertDescription>{statusMessage}</AlertDescription>
            </Alert>
          )}
          {errorMessage && (
            <Alert variant="destructive">
              <AlertDescription>{errorMessage}</AlertDescription>
            </Alert>
          )}
        </CardContent>
      </Card>
    );
  }

  return (
    <Card>
      <CardHeader>
        <CardTitle>{t('payment.title', { defaultValue: 'Zahlung' })}</CardTitle>
      </CardHeader>
      <CardContent className="space-y-6">
        <div className="flex items-center justify-between flex-wrap gap-3">
          <div>
            <p className="text-sm text-gray-500">{t('payment.total_due', { defaultValue: 'Gesamtbetrag' })}</p>
            <p className="text-lg font-semibold">{formatCurrency(price, currency)}</p>
          </div>
          <div className="inline-flex rounded-md shadow-sm" role="group">
            <Button
              type="button"
              variant={provider === 'stripe' ? 'default' : 'outline'}
              onClick={() => setProvider('stripe')}
            >
              Stripe
            </Button>
            <Button
              type="button"
              variant={provider === 'paypal' ? 'default' : 'outline'}
              onClick={() => setProvider('paypal')}
            >
              PayPal
            </Button>
          </div>
        </div>

        {provider === 'stripe' ? (
          <Elements stripe={stripePromise} options={{ appearance: { theme: 'stripe' } }}>
            <StripeCardForm
              packageId={packageId}
              csrfToken={csrfToken}
              amountLabel={formatCurrency(price, currency)}
              onSuccess={() => {
                setStatusMessage(t('payment.success_stripe', { defaultValue: 'Stripe-Zahlung erfolgreich.' }));
                onSuccess();
              }}
              onError={(message) => setErrorMessage(message)}
            />
          </Elements>
        ) : (
          <PayPalSection
            packageId={packageId}
            amount={price}
            currency={currency}
            clientId={paypalClientId}
            csrfToken={csrfToken}
            onSuccess={() => {
              setStatusMessage(t('payment.success_paypal', { defaultValue: 'PayPal-Zahlung erfolgreich.' }));
              onSuccess();
            }}
            onError={(message) => setErrorMessage(message)}
          />
        )}

        {statusMessage && (
          <Alert variant="success">
            <AlertDescription>{statusMessage}</AlertDescription>
          </Alert>
        )}

        {errorMessage && (
          <Alert variant="destructive">
            <AlertDescription>{errorMessage}</AlertDescription>
          </Alert>
        )}
      </CardContent>
    </Card>
  );
}

interface StripeCardFormProps {
  packageId: number;
  csrfToken: string;
  amountLabel: string;
  onSuccess: () => void;
  onError: (message: string) => void;
}

const StripeCardForm: React.FC<StripeCardFormProps> = ({ packageId, csrfToken, amountLabel, onSuccess, onError }) => {
  const { t } = useTranslation('marketing');
  const stripe = useStripe();
  const elements = useElements();
  const [isSubmitting, setIsSubmitting] = useState(false);
  const [localError, setLocalError] = useState<string | null>(null);

  const handleSubmit = async (event: React.FormEvent<HTMLFormElement>) => {
    event.preventDefault();

    if (!stripe || !elements) {
      return;
    }

    const cardElement = elements.getElement(CardElement);
    if (!cardElement) {
      setLocalError('Card element not found.');
      return;
    }

    try {
      setIsSubmitting(true);
      setLocalError(null);

      const { client_secret: clientSecret, payment_intent_id: paymentIntentId } = await postJson<{
        client_secret: string;
        payment_intent_id: string;
      }>('/purchase/stripe/intent', { package_id: packageId }, csrfToken);

      const confirmation = await stripe.confirmCardPayment(clientSecret, {
        payment_method: {
          card: cardElement,
        },
      });

      if (confirmation.error) {
        throw new Error(confirmation.error.message || 'Card confirmation failed.');
      }

      if (confirmation.paymentIntent?.status !== 'succeeded') {
        throw new Error('Stripe did not confirm the payment.');
      }

      await postJson('/purchase/stripe/complete', {
        package_id: packageId,
        payment_intent_id: confirmation.paymentIntent.id || paymentIntentId,
      }, csrfToken);

      onSuccess();
    } catch (error) {
      const message = (error as Error).message || 'Stripe payment failed.';
      setLocalError(message);
      onError(message);
    } finally {
      setIsSubmitting(false);
    }
  };

  return (
    <form onSubmit={handleSubmit} className="space-y-4">
      <div className="space-y-2">
        <label htmlFor="card-element" className="text-sm font-medium">
          {t('payment.card_details', { defaultValue: 'Kartendaten' })}
        </label>
        <div className="p-3 border border-gray-300 rounded-md">
          <CardElement
            options={{
              hidePostalCode: true,
              style: {
                base: {
                  fontSize: '16px',
                  color: '#424770',
                  '::placeholder': {
                    color: '#aab7c4',
                  },
                },
              },
            }}
          />
        </div>
        {localError && (
          <Alert variant="destructive">
            <AlertDescription>{localError}</AlertDescription>
          </Alert>
        )}
      </div>
      <Button type="submit" className="w-full" disabled={!stripe || isSubmitting}>
        {isSubmitting && <Loader2 className="h-4 w-4 animate-spin mr-2" />}
        {t('payment.submit', {
          defaultValue: 'Jetzt bezahlen',
          price: amountLabel,
        })}
      </Button>
    </form>
  );
};

interface PayPalSectionProps {
  packageId: number;
  amount: number;
  currency: string;
  clientId?: string | null;
  csrfToken: string;
  onSuccess: () => void;
  onError: (message: string) => void;
}

const PayPalSection: React.FC<PayPalSectionProps> = ({
  packageId,
  amount,
  currency,
  clientId,
  csrfToken,
  onSuccess,
  onError,
}) => {
  const { t } = useTranslation('marketing');
  const containerRef = useRef<HTMLDivElement | null>(null);
  const [isSdkReady, setIsSdkReady] = useState(false);
  const [isProcessing, setIsProcessing] = useState(false);
  const [localError, setLocalError] = useState<string | null>(null);

  useEffect(() => {
    if (!clientId) {
      const message = t('payment.paypal_missing_key', { defaultValue: 'PayPal ist derzeit nicht konfiguriert.' });
      setLocalError(message);
      onError(message);
      return;
    }

    if (window.paypal) {
      setIsSdkReady(true);
      return;
    }

    const script = document.createElement('script');
    script.src = `https://www.paypal.com/sdk/js?client-id=${clientId}&currency=${currency}&intent=capture&components=buttons`;
    script.async = true;
    script.onload = () => setIsSdkReady(true);
    script.onerror = () => {
      const message = t('payment.paypal_sdk_failed', { defaultValue: 'PayPal-SDK konnte nicht geladen werden.' });
      setLocalError(message);
      onError(message);
    };
    document.body.appendChild(script);

    return () => {
      script.remove();
    };
  }, [clientId, currency, onError, t]);

  useEffect(() => {
    if (!isSdkReady || !window.paypal || !containerRef.current) {
      return;
    }

    const buttons = window.paypal.Buttons({
      style: {
        layout: 'vertical',
        color: 'gold',
        shape: 'rect',
      },
      createOrder: async () => {
        try {
          setIsProcessing(true);
          const { order_id: orderId } = await postJson<{ order_id: string }>('/purchase/paypal/order', {
            package_id: packageId,
          }, csrfToken);
          return orderId;
        } catch (error) {
          const message = (error as Error).message || 'PayPal order creation failed.';
          setLocalError(message);
          onError(message);
          setIsProcessing(false);
          throw error;
        }
      },
      onApprove: async (data: { orderID: string }) => {
        try {
          await postJson('/purchase/paypal/capture', {
            order_id: data.orderID,
            package_id: packageId,
          }, csrfToken);
          setIsProcessing(false);
          setLocalError(null);
          onSuccess();
        } catch (error) {
          const message = (error as Error).message || 'PayPal capture failed.';
          setLocalError(message);
          onError(message);
          setIsProcessing(false);
        }
      },
      onError: (error: Error) => {
        const message = error?.message || 'PayPal payment failed.';
        setLocalError(message);
        onError(message);
        setIsProcessing(false);
      },
    });

    buttons.render(containerRef.current);

    return () => {
      try {
        buttons.close();
      } catch (error) {
        // ignore close errors
      }
    };
  }, [csrfToken, isSdkReady, onError, onSuccess, packageId]);

  return (
    <div className="space-y-4">
      <div ref={containerRef} />
      {isProcessing && (
        <div className="flex items-center space-x-2 text-sm text-gray-600">
          <Loader2 className="h-4 w-4 animate-spin" />
          <span>{t('payment.processing_paypal', { defaultValue: 'PayPal-Zahlung wird verarbeitet �' })}</span>
        </div>
      )}
      {localError && (
        <Alert variant="destructive">
          <AlertDescription>{localError}</AlertDescription>
        </Alert>
      )}
      <p className="text-xs text-gray-500">
        {t('payment.paypal_hint', {
          defaultValue: 'Der Betrag von {{amount}} wird bei PayPal angezeigt.',
          amount: formatCurrency(amount, currency),
        })}
      </p>
    </div>
  );
};
