import { useState, useCallback } from 'react';
import { Input } from '@/components/ui/input';
import { Select, SelectOption } from '@/components/ui/select';
import { DatePicker } from '@/components/ui/date-picker';
import { FileUpload } from '@/components/ui/file-upload';
import { Button } from '@/components/ui/button';
import { Label } from '@/components/ui/label';
import { cn } from '@/lib/utils';

export interface FormField {
  name: string;
  type:
  | 'text'
  | 'email'
  | 'password'
  | 'number'
  | 'textarea'
  | 'select'
  | 'date'
  | 'file';
  label: string;
  placeholder?: string;
  required?: boolean;
  disabled?: boolean;
  defaultValue?: any;
  validation?: (value: any) => string | null;
  // Options pour le type select
  options?: SelectOption[];
  // Options pour le type file
  accept?: string;
  multiple?: boolean;
  maxSize?: number;
  // Options pour le type date
  minDate?: Date;
  maxDate?: Date;
  mode?: 'single' | 'range';
}

export interface FormBuilderProps {
  fields: FormField[];
  onSubmit: (data: Record<string, any>) => void;
  submitLabel?: string;
  className?: string;
  disabled?: boolean;
}

/**
 * Composant FormBuilder pour créer des formulaires dynamiques à partir de configuration.
 */
export function FormBuilder({
  fields,
  onSubmit,
  submitLabel = 'Submit',
  className,
  disabled = false,
}: FormBuilderProps) {
  const [formData, setFormData] = useState<Record<string, any>>(() => {
    const initial: Record<string, any> = {};
    fields.forEach((field) => {
      if (field.defaultValue !== undefined) {
        initial[field.name] = field.defaultValue;
      } else if (field.type === 'select') {
        initial[field.name] = field.multiple ? [] : '';
      } else if (field.type === 'file') {
        initial[field.name] = field.multiple ? [] : null;
      } else if (field.type === 'date') {
        initial[field.name] =
          field.mode === 'range' ? { start: null, end: null } : null;
      } else {
        initial[field.name] = '';
      }
    });
    return initial;
  });

  const [errors, setErrors] = useState<Record<string, string>>({});
  const [touched, setTouched] = useState<Record<string, boolean>>({});

  const validateField = useCallback(
    (field: FormField, value: any): string | null => {
      // Validation required
      if (field.required) {
        if (
          value === null ||
          value === undefined ||
          value === '' ||
          (Array.isArray(value) && value.length === 0) ||
          (typeof value === 'object' &&
            field.type === 'date' &&
            field.mode === 'range' &&
            (!value.start || !value.end))
        ) {
          return `${field.label} is required`;
        }
      }

      // Validation email
      if (field.type === 'email' && value) {
        const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
        if (!emailRegex.test(value)) {
          return 'Please enter a valid email address';
        }
      }

      // Validation personnalisée
      if (field.validation) {
        const customError = field.validation(value);
        if (customError) {
          return customError;
        }
      }

      return null;
    },
    [],
  );

  const handleFieldChange = useCallback(
    (fieldName: string, value: any) => {
      setFormData((prev) => ({
        ...prev,
        [fieldName]: value,
      }));

      // Valider le champ si déjà touché
      if (touched[fieldName]) {
        const field = fields.find((f) => f.name === fieldName);
        if (field) {
          const error = validateField(field, value);
          setErrors((prev) => {
            if (error) {
              return { ...prev, [fieldName]: error };
            } else {
              const newErrors = { ...prev };
              delete newErrors[fieldName];
              return newErrors;
            }
          });
        }
      }
    },
    [fields, touched, validateField],
  );

  const handleFieldBlur = useCallback(
    (fieldName: string) => {
      setTouched((prev) => ({ ...prev, [fieldName]: true }));

      const field = fields.find((f) => f.name === fieldName);
      if (field) {
        const value = formData[fieldName];
        const error = validateField(field, value);
        setErrors((prev) => {
          if (error) {
            return { ...prev, [fieldName]: error };
          } else {
            const newErrors = { ...prev };
            delete newErrors[fieldName];
            return newErrors;
          }
        });
      }
    },
    [fields, formData, validateField],
  );

  const handleSubmit = useCallback(
    (e: React.FormEvent) => {
      e.preventDefault();

      // Marquer tous les champs comme touchés
      const allTouched: Record<string, boolean> = {};
      const newErrors: Record<string, string> = {};

      fields.forEach((field) => {
        allTouched[field.name] = true;
        const value = formData[field.name];
        const error = validateField(field, value);
        if (error) {
          newErrors[field.name] = error;
        }
      });

      setTouched(allTouched);
      setErrors(newErrors);

      // Si pas d'erreurs, soumettre
      if (Object.keys(newErrors).length === 0) {
        onSubmit(formData);
      }
    },
    [fields, formData, validateField, onSubmit],
  );

  const renderField = (field: FormField, hasError: boolean) => {
    switch (field.type) {
      case 'text':
      case 'email':
      case 'password':
      case 'number':
        return (
          <Input
            type={field.type}
            value={formData[field.name] || ''}
            onChange={(e) => handleFieldChange(field.name, e.target.value)}
            onBlur={() => handleFieldBlur(field.name)}
            placeholder={field.placeholder}
            disabled={disabled || field.disabled}
            className={hasError ? 'border-destructive' : ''}
          />
        );

      case 'textarea':
        return (
          <textarea
            value={formData[field.name] || ''}
            onChange={(e) => handleFieldChange(field.name, e.target.value)}
            onBlur={() => handleFieldBlur(field.name)}
            placeholder={field.placeholder}
            disabled={disabled || field.disabled}
            className={cn(
              'flex min-h-[80px] w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50',
              hasError && 'border-destructive',
            )}
          />
        );

      case 'select':
        return (
          <Select
            options={field.options || []}
            value={formData[field.name]}
            onChange={(value) => handleFieldChange(field.name, value)}
            multiple={field.multiple}
            placeholder={
              field.placeholder || `Select ${field.label.toLowerCase()}`
            }
            disabled={disabled || field.disabled}
          />
        );

      case 'date':
        return (
          <DatePicker
            value={formData[field.name]}
            onChange={(value) => handleFieldChange(field.name, value)}
            mode={field.mode || 'single'}
            minDate={field.minDate}
            maxDate={field.maxDate}
            placeholder={
              field.placeholder || `Select ${field.label.toLowerCase()}`
            }
            disabled={disabled || field.disabled}
          />
        );

      case 'file':
        return (
          <FileUpload
            onFileSelect={(files) => handleFieldChange(field.name, files)}
            accept={field.accept}
            multiple={field.multiple}
            maxSize={field.maxSize}
            showPreview={true}
            disabled={disabled || field.disabled}
          />
        );

      default:
        return null;
    }
  };

  return (
    <form onSubmit={handleSubmit} className={cn('space-y-6', className)}>
      {fields.map((field) => {
        const fieldError = errors[field.name];
        const isTouched = touched[field.name];
        const showError = isTouched && fieldError;

        return (
          <div key={field.name} className="space-y-2">
            <Label htmlFor={field.name}>
              {field.label}
              {field.required && (
                <span className="text-destructive ml-1">*</span>
              )}
            </Label>
            {renderField(field, !!showError)}
            {showError && (
              <p className="text-sm text-destructive">{fieldError}</p>
            )}
          </div>
        );
      })}

      <Button type="submit" disabled={disabled}>
        {submitLabel}
      </Button>
    </form>
  );
}
