'use client';

import * as React from 'react';
import { Suspense, type ReactNode, type ComponentType } from 'react';
import { cn } from '@djangocfg/ui-core/lib';
import { useAppT } from '@djangocfg/i18n';

// ============================================================================
// Loading Fallback Components
// ============================================================================

export interface LoadingFallbackProps {
  /** Minimum height of the loading container */
  minHeight?: string | number;
  /** Show loading text */
  showText?: boolean;
  /** Custom loading text */
  text?: string;
  /** Additional CSS classes */
  className?: string;
}

/**
 * Spinner - Simple spinning loader
 */
export function Spinner({ className }: { className?: string }) {
  const t = useAppT();
  const loadingLabel = t('ui.states.loading');

  return (
    <div
      className={cn(
        'inline-block h-8 w-8 animate-spin rounded-full',
        'border-4 border-solid border-current border-r-transparent',
        'align-[-0.125em] motion-reduce:animate-[spin_1.5s_linear_infinite]',
        className
      )}
      role="status"
      aria-label={loadingLabel}
    />
  );
}

/**
 * LoadingFallback - Default loading state for lazy components
 */
export function LoadingFallback({
  minHeight = 200,
  showText = true,
  text,
  className,
}: LoadingFallbackProps) {
  const t = useAppT();
  const loadingText = text ?? t('ui.form.loading');
  const height = typeof minHeight === 'number' ? `${minHeight}px` : minHeight;

  return (
    <div
      className={cn(
        'flex items-center justify-center bg-muted/30 rounded-lg',
        className
      )}
      style={{ minHeight: height }}
    >
      <div className="text-center">
        <Spinner className="text-primary" />
        {showText && (
          <p className="mt-3 text-sm text-muted-foreground">{loadingText}</p>
        )}
      </div>
    </div>
  );
}

/**
 * CardLoadingFallback - Loading state styled as a card
 */
export function CardLoadingFallback({
  title,
  description,
  minHeight = 200,
  className,
}: {
  title?: string;
  description?: string;
  minHeight?: string | number;
  className?: string;
}) {
  const t = useAppT();
  const cardTitle = title ?? t('ui.states.loading');
  const height = typeof minHeight === 'number' ? `${minHeight}px` : minHeight;

  return (
    <div
      className={cn(
        'relative bg-card rounded-lg border border-border overflow-hidden',
        className
      )}
    >
      <div className="p-4 border-b border-border bg-muted/50">
        <h6 className="text-sm font-semibold text-foreground">{cardTitle}</h6>
        {description && (
          <p className="text-xs text-muted-foreground mt-1">{description}</p>
        )}
      </div>
      <div className="p-4">
        <div
          className="flex justify-center items-center"
          style={{ minHeight: height }}
        >
          <Spinner className="text-primary" />
        </div>
      </div>
    </div>
  );
}

/**
 * MapLoadingFallback - Loading state for map components
 */
export function MapLoadingFallback({
  minHeight = 400,
  className,
}: {
  minHeight?: string | number;
  className?: string;
}) {
  const t = useAppT();
  const loadingText = t('ui.form.loading');
  const height = typeof minHeight === 'number' ? `${minHeight}px` : minHeight;

  return (
    <div
      className={cn(
        'relative bg-muted/50 rounded-lg overflow-hidden',
        'flex items-center justify-center',
        className
      )}
      style={{ minHeight: height }}
    >
      <div className="text-center">
        <div className="relative">
          <Spinner className="text-primary h-10 w-10" />
          <div className="absolute inset-0 flex items-center justify-center">
            <svg
              className="h-5 w-5 text-muted-foreground"
              fill="none"
              viewBox="0 0 24 24"
              stroke="currentColor"
            >
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth={2}
                d="M17.657 16.657L13.414 20.9a1.998 1.998 0 01-2.827 0l-4.244-4.243a8 8 0 1111.314 0z"
              />
              <path
                strokeLinecap="round"
                strokeLinejoin="round"
                strokeWidth={2}
                d="M15 11a3 3 0 11-6 0 3 3 0 016 0z"
              />
            </svg>
          </div>
        </div>
        <p className="mt-3 text-sm text-muted-foreground">{loadingText}</p>
      </div>
    </div>
  );
}

// ============================================================================
// Lazy Wrapper
// ============================================================================

export interface LazyWrapperProps {
  children: ReactNode;
  /** Custom fallback component */
  fallback?: ReactNode;
  /** Use card-style fallback */
  card?: boolean;
  /** Card title (when card=true) */
  cardTitle?: string;
  /** Card description (when card=true) */
  cardDescription?: string;
  /** Minimum height for fallback */
  minHeight?: string | number;
  /** Additional CSS classes for fallback */
  className?: string;
}

/**
 * LazyWrapper - Suspense wrapper with configurable fallbacks
 *
 * @example
 * // Basic usage
 * <LazyWrapper>
 *   <LazyComponent />
 * </LazyWrapper>
 *
 * @example
 * // Card style fallback
 * <LazyWrapper card cardTitle="Diagram" minHeight={300}>
 *   <Mermaid chart={...} />
 * </LazyWrapper>
 *
 * @example
 * // Custom fallback
 * <LazyWrapper fallback={<MyCustomLoader />}>
 *   <HeavyComponent />
 * </LazyWrapper>
 */
export function LazyWrapper({
  children,
  fallback,
  card = false,
  cardTitle,
  cardDescription,
  minHeight = 200,
  className,
}: LazyWrapperProps) {
  const defaultFallback = card ? (
    <CardLoadingFallback
      title={cardTitle}
      description={cardDescription}
      minHeight={minHeight}
      className={className}
    />
  ) : (
    <LoadingFallback minHeight={minHeight} className={className} />
  );

  return <Suspense fallback={fallback ?? defaultFallback}>{children}</Suspense>;
}

// ============================================================================
// Lazy Component Factory
// ============================================================================

export interface CreateLazyComponentOptions<P> {
  /** Loading fallback component */
  fallback?: ReactNode | ((props: P) => ReactNode);
  /** Display name for the component */
  displayName?: string;
}

/**
 * createLazyComponent - Factory for creating lazy-loaded components
 *
 * @example
 * const LazyMermaid = createLazyComponent(
 *   () => import('./Mermaid.client'),
 *   {
 *     displayName: 'Mermaid',
 *     fallback: <CardLoadingFallback title="Diagram" />,
 *   }
 * );
 */
export function createLazyComponent<P extends object>(
  loader: () => Promise<{ default: ComponentType<P> }>,
  options: CreateLazyComponentOptions<P> = {}
): ComponentType<P> {
  const LazyComponent = React.lazy(loader);

  const WrappedComponent = (props: P) => {
    const fallback =
      typeof options.fallback === 'function'
        ? options.fallback(props)
        : options.fallback ?? <LoadingFallback />;

    return (
      <Suspense fallback={fallback}>
        <LazyComponent {...props} />
      </Suspense>
    );
  };

  WrappedComponent.displayName = options.displayName ?? 'LazyComponent';

  return WrappedComponent;
}
