/**
 * StripeElementsWrapper Component
 * Provider component for Stripe Elements integration
 * Epic: OQI-005 Pagos y Stripe
 *
 * IMPORTANT: This component is required for PCI-DSS compliance.
 * All payment forms must be wrapped with this provider.
 */

import React, { useState, useEffect, useMemo } from 'react';
import { Elements } from '@stripe/react-stripe-js';
import { loadStripe, Stripe, StripeElementsOptions } from '@stripe/stripe-js';
import {
  CreditCard,
  AlertCircle,
  Loader2,
  ShieldCheck,
} from 'lucide-react';

// Types
export interface StripeConfig {
  publicKey: string;
  locale?: 'en' | 'es' | 'auto';
  appearance?: 'stripe' | 'night' | 'flat';
}

export interface StripeElementsWrapperProps {
  children: React.ReactNode;
  config?: Partial<StripeConfig>;
  clientSecret?: string;
  onReady?: () => void;
  onError?: (error: Error) => void;
  showLoadingState?: boolean;
  fallbackComponent?: React.ReactNode;
}

// Default Stripe appearance for dark theme
const DARK_THEME_APPEARANCE: StripeElementsOptions['appearance'] = {
  theme: 'night',
  variables: {
    colorPrimary: '#3b82f6',
    colorBackground: '#1e293b',
    colorText: '#f1f5f9',
    colorDanger: '#ef4444',
    fontFamily: 'Inter, system-ui, sans-serif',
    fontSizeBase: '14px',
    borderRadius: '8px',
    spacingUnit: '4px',
  },
  rules: {
    '.Input': {
      backgroundColor: '#0f172a',
      border: '1px solid #334155',
      boxShadow: 'none',
    },
    '.Input:focus': {
      borderColor: '#3b82f6',
      boxShadow: '0 0 0 1px #3b82f6',
    },
    '.Input--invalid': {
      borderColor: '#ef4444',
    },
    '.Label': {
      color: '#94a3b8',
      fontSize: '12px',
      fontWeight: '500',
    },
    '.Error': {
      color: '#ef4444',
      fontSize: '12px',
    },
  },
};

// Stripe public key from environment
// Declare process.env for compatibility with non-Vite environments
declare const process: { env: Record<string, string | undefined> } | undefined;
const STRIPE_PUBLIC_KEY = import.meta.env.VITE_STRIPE_PUBLIC_KEY ||
  (typeof process !== 'undefined' ? process?.env?.REACT_APP_STRIPE_PUBLIC_KEY : '') || '';

// Loading component
const LoadingState: React.FC = () => (
  <div className="flex flex-col items-center justify-center p-8 bg-slate-900/50 rounded-lg border border-slate-800">
    <div className="relative">
      <Loader2 className="w-8 h-8 text-blue-500 animate-spin" />
      <CreditCard className="w-4 h-4 text-slate-400 absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2" />
    </div>
    <p className="text-slate-400 text-sm mt-4">Loading payment system...</p>
    <div className="flex items-center gap-2 mt-2">
      <ShieldCheck className="w-4 h-4 text-emerald-500" />
      <span className="text-emerald-500 text-xs">Secured by Stripe</span>
    </div>
  </div>
);

// Error component
const ErrorState: React.FC<{ error: string; onRetry?: () => void }> = ({ error, onRetry }) => (
  <div className="flex flex-col items-center justify-center p-8 bg-red-900/20 rounded-lg border border-red-800/50">
    <AlertCircle className="w-8 h-8 text-red-400 mb-4" />
    <p className="text-red-400 font-medium">Payment System Error</p>
    <p className="text-slate-400 text-sm mt-2 text-center max-w-md">{error}</p>
    {onRetry && (
      <button
        onClick={onRetry}
        className="mt-4 px-4 py-2 bg-slate-800 text-white rounded-lg hover:bg-slate-700 transition-colors"
      >
        Retry
      </button>
    )}
  </div>
);

// Configuration missing component
const ConfigMissing: React.FC = () => (
  <div className="flex flex-col items-center justify-center p-8 bg-amber-900/20 rounded-lg border border-amber-800/50">
    <AlertCircle className="w-8 h-8 text-amber-400 mb-4" />
    <p className="text-amber-400 font-medium">Stripe Configuration Missing</p>
    <p className="text-slate-400 text-sm mt-2 text-center max-w-md">
      The Stripe public key is not configured. Please set VITE_STRIPE_PUBLIC_KEY
      in your environment variables.
    </p>
    <div className="mt-4 bg-slate-800 rounded p-3 font-mono text-xs text-slate-400">
      VITE_STRIPE_PUBLIC_KEY=pk_test_...
    </div>
  </div>
);

const StripeElementsWrapper: React.FC<StripeElementsWrapperProps> = ({
  children,
  config = {},
  clientSecret,
  onReady,
  onError,
  showLoadingState = true,
  fallbackComponent,
}) => {
  const [stripePromise, setStripePromise] = useState<Promise<Stripe | null> | null>(null);
  const [isLoading, setIsLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  // Merge config with defaults
  const stripeConfig = useMemo(() => ({
    publicKey: config.publicKey || STRIPE_PUBLIC_KEY,
    locale: config.locale || 'auto',
    appearance: config.appearance || 'night',
  }), [config]);

  // Initialize Stripe
  useEffect(() => {
    if (!stripeConfig.publicKey) {
      setIsLoading(false);
      setError('Stripe public key is not configured');
      return;
    }

    const initStripe = async () => {
      try {
        setIsLoading(true);
        setError(null);

        const stripe = loadStripe(stripeConfig.publicKey, {
          locale: stripeConfig.locale as 'en' | 'es' | undefined,
        });

        setStripePromise(stripe);

        // Wait for Stripe to load and verify
        const stripeInstance = await stripe;
        if (!stripeInstance) {
          throw new Error('Failed to initialize Stripe');
        }

        setIsLoading(false);
        onReady?.();
      } catch (err) {
        const errorMessage = err instanceof Error ? err.message : 'Unknown error loading Stripe';
        setError(errorMessage);
        setIsLoading(false);
        onError?.(err instanceof Error ? err : new Error(errorMessage));
      }
    };

    initStripe();
  }, [stripeConfig.publicKey, stripeConfig.locale, onReady, onError]);

  // Retry handler
  const handleRetry = () => {
    setError(null);
    setIsLoading(true);
    // Re-trigger useEffect by updating state
    setStripePromise(null);
  };

  // Elements options
  const elementsOptions: StripeElementsOptions = useMemo(() => ({
    clientSecret: clientSecret || undefined,
    appearance: DARK_THEME_APPEARANCE,
    loader: 'auto',
  }), [clientSecret]);

  // Check for missing config
  if (!stripeConfig.publicKey) {
    return fallbackComponent || <ConfigMissing />;
  }

  // Show loading state
  if (isLoading && showLoadingState) {
    return fallbackComponent || <LoadingState />;
  }

  // Show error state
  if (error) {
    return fallbackComponent || <ErrorState error={error} onRetry={handleRetry} />;
  }

  // Render with Stripe Elements
  if (!stripePromise) {
    return fallbackComponent || <LoadingState />;
  }

  return (
    <Elements stripe={stripePromise} options={elementsOptions}>
      {children}
    </Elements>
  );
};

// Higher-order component for wrapping payment forms
export function withStripeElements<P extends object>(
  WrappedComponent: React.ComponentType<P>,
  config?: Partial<StripeConfig>
): React.FC<P> {
  return function WithStripeElementsWrapper(props: P) {
    return (
      <StripeElementsWrapper config={config}>
        <WrappedComponent {...props} />
      </StripeElementsWrapper>
    );
  };
}

// Hook to check if Stripe is available
export function useStripeAvailable(): boolean {
  const [available, setAvailable] = useState(false);

  useEffect(() => {
    setAvailable(!!STRIPE_PUBLIC_KEY);
  }, []);

  return available;
}

export default StripeElementsWrapper;
