import React, { useState, useEffect, useCallback, useRef } from 'react';
import { useLanguage } from '../../../providers/language/LanguageContext';
import api from '../../../api';
import styles from './FormGeneratorForm.module.css';
import {
  attributeTypeToInputType,
  isTextareaType,
  isSelectType,
  isMultiselectType,
  isMultilingualType,
  isCheckboxType,
  isFileType,
  isNumberType,
  isDateTimeType,
  getDefaultValueForType
} from '../../../utils/attributeTypeMapper';
import type { AttributeType } from '../../../utils/attributeTypeMapper';

// Helper function to detect TextMultilingual objects
// TextMultilingual has structure: { en: string, ge?: string, fr?: string, it?: string }
const isTextMultilingual = (value: any): boolean => {
  if (!value || typeof value !== 'object' || Array.isArray(value) || value instanceof Date) {
    return false;
  }
  // Check if it has 'en' property (required) and optionally other language codes
  return 'en' in value && typeof value.en === 'string';
};

// Note: Field types are determined ONLY by the explicit 'type' property.
// FormGeneratorForm does NOT infer types from field names.

  // Attribute definition interface (matches backend structure)
export interface AttributeDefinition {
  name: string;
  type: AttributeType;
  label: string;
  description?: string;
  required?: boolean;
  default?: any;
  options?: AttributeOption[] | string | string[]; // Array of options or reference like "user.role"
  validation?: any;
  ui?: any;
  readonly?: boolean;
  editable?: boolean;
  visible?: boolean;
  order?: number;
  placeholder?: string;
  minRows?: number; // For textarea types
  maxRows?: number; // For textarea types
}

export interface AttributeOption {
  value: string | number;
  label: string | { [language: string]: string };
}

// FormGeneratorForm props
export interface FormGeneratorFormProps<T = any> {
  // Entity type for fetching attributes (e.g., "Prompt", "User", "FileItem")
  // Required if attributes are not provided
  entityType?: string;
  // Initial form data (for edit mode)
  data?: T;
  // Form mode: 'create' | 'edit' | 'display'
  mode?: 'create' | 'edit' | 'display';
  // Callback when form is submitted
  onSubmit: (formData: T) => void | Promise<void>;
  // Optional cancel callback
  onCancel?: () => void;
  // Button text customization
  submitButtonText?: string;
  cancelButtonText?: string;
  // Show/hide buttons
  showButtons?: boolean;
  // Custom className
  className?: string;
  // Optional: Pre-fetched attributes (if already available)
  attributes?: AttributeDefinition[];
  // Optional: Custom field filtering function
  filterFields?: (attributes: AttributeDefinition[]) => AttributeDefinition[];
  // Optional: Custom field transformation function
  transformField?: (attribute: AttributeDefinition) => AttributeDefinition;
  // Optional: Custom validation function
  customValidator?: (formData: T, attributes: AttributeDefinition[]) => Record<string, string>;
  // Optional: Feature instance ID for feature-scoped options (replaces {instanceId} in API paths)
  instanceId?: string;
}

// FormGeneratorForm component - Backend-driven form generation
export function FormGeneratorForm<T extends Record<string, any>>({
  entityType,
  data,
  mode = 'edit',
  onSubmit,
  onCancel,
  submitButtonText,
  cancelButtonText,
  showButtons = true,
  className = '',
  attributes: providedAttributes,
  filterFields,
  transformField,
  customValidator,
  instanceId
}: FormGeneratorFormProps<T>) {
  const { t } = useLanguage();
  
  const [formData, setFormData] = useState<T>(data || {} as T);
  const [errors, setErrors] = useState<Record<string, string>>({});
  const [fieldFocused, setFieldFocused] = useState<Record<string, boolean>>({});
  const [attributes, setAttributes] = useState<AttributeDefinition[]>(providedAttributes || []);
  const [loadingAttributes, setLoadingAttributes] = useState(!providedAttributes);
  const [optionsCache, setOptionsCache] = useState<Record<string, Array<{ value: string | number; label: string }>>>({});
  const [loadingOptions, setLoadingOptions] = useState<Record<string, boolean>>({});
  const [submitting, setSubmitting] = useState(false);
  // Track which option keys have been fetched or are being fetched (using ref to avoid re-renders)
  const fetchedOrFetchingOptions = useRef<Set<string>>(new Set());
  
  // Helper to resolve API paths with {instanceId} placeholder - memoized to prevent useEffect re-runs
  const resolveApiPath = useCallback((path: string): string => {
    if (path.includes('{instanceId}')) {
      const resolvedInstanceId = instanceId || (data as any)?.featureInstanceId;
      if (!resolvedInstanceId) {
        console.warn(`API path "${path}" requires instanceId but none provided`);
        return path;
      }
      return path.replace('{instanceId}', resolvedInstanceId);
    }
    return path;
  }, [instanceId, data]);

  // Fetch attributes from backend
  useEffect(() => {
    const fetchAttributes = async () => {
      if (providedAttributes) {
        setAttributes(providedAttributes);
        setLoadingAttributes(false);
        return;
      }

      if (!entityType) {
        console.warn('FormGeneratorForm: entityType is required when attributes are not provided');
        setAttributes([]);
        setLoadingAttributes(false);
        return;
      }

      try {
        setLoadingAttributes(true);
        const response = await api.get(`/api/attributes/${entityType}`);
        
        // Extract attributes from response
        let attrs: AttributeDefinition[] = [];
        if (response.data?.attributes && Array.isArray(response.data.attributes)) {
          attrs = response.data.attributes;
        } else if (Array.isArray(response.data)) {
          attrs = response.data;
        } else if (response.data && typeof response.data === 'object') {
          const keys = Object.keys(response.data);
          for (const key of keys) {
            if (Array.isArray(response.data[key])) {
              attrs = response.data[key];
              break;
            }
          }
        }
        
        setAttributes(attrs);
      } catch (error: any) {
        console.error(`Error fetching attributes for ${entityType}:`, error);
        setAttributes([]);
      } finally {
        setLoadingAttributes(false);
      }
    };

    fetchAttributes();
  }, [entityType, providedAttributes]);

  // Filter attributes based on mode
  const getFilteredAttributes = useCallback((): AttributeDefinition[] => {
    let filtered = [...attributes];

    // Apply custom filter if provided
    if (filterFields) {
      filtered = filterFields(filtered);
    } else {
      // Default filtering based on mode
      // Note: readonly fields (editable === false) should be shown but rendered as read-only
      // Only hide fields where visible === false explicitly
      if (mode === 'edit') {
        // Show all visible fields (readonly fields are rendered as non-editable in renderField)
        filtered = filtered.filter(attr => attr.visible !== false);
      } else if (mode === 'create') {
        // In create mode, hide truly non-editable fields (user can't set them)
        filtered = filtered.filter(attr => attr.visible !== false && attr.editable !== false);
      } else if (mode === 'display') {
        filtered = filtered.filter(attr => attr.visible !== false);
      }
    }

    // Apply custom transformation if provided
    if (transformField) {
      filtered = filtered.map(transformField);
    }

    // Sort by order if available
    filtered.sort((a, b) => {
      const orderA = a.order ?? 999;
      const orderB = b.order ?? 999;
      return orderA - orderB;
    });

    return filtered;
  }, [attributes, mode, filterFields, transformField]);

  // Initialize form data with defaults
  useEffect(() => {
    // Helper to check if a field should be treated as multilingual
    // Only use explicit type - do NOT infer from field name
    const isMultilingual = (attr: AttributeDefinition) => {
      return isMultilingualType(attr.type as AttributeType);
    };
    
    if (data) {
      // Ensure TextMultilingual fields are properly initialized
      const processedData: any = { ...data };
      const filteredAttrs = getFilteredAttributes();
      filteredAttrs.forEach(attr => {
        if (isMultilingual(attr) && processedData[attr.name]) {
          // If it's already a TextMultilingual object, keep it
          if (!isTextMultilingual(processedData[attr.name])) {
            // If it's a string, convert to TextMultilingual
            if (typeof processedData[attr.name] === 'string') {
              processedData[attr.name] = { en: processedData[attr.name] };
            }
          }
        }
      });
      setFormData(processedData as T);
    } else {
      const filteredAttrs = getFilteredAttributes();
      const initialData: any = {};
      filteredAttrs.forEach(attr => {
        if (attr.default !== undefined) {
          initialData[attr.name] = attr.default;
        } else if (isMultilingual(attr)) {
          // Initialize TextMultilingual fields with empty object
          initialData[attr.name] = { en: '' };
        } else {
          initialData[attr.name] = getDefaultValueForType(attr.type);
        }
      });
      setFormData(initialData as T);
    }
    setErrors({});
    setFieldFocused({});
  }, [data, getFilteredAttributes]);

  // Fetch options for fields with optionsReference (API path)
  // Backend provides options in standardized format: { value, label }
  // OPTIMIZED: Only fetch options that are not already fetched or being fetched
  useEffect(() => {
    const fetchOptions = async () => {
      const filteredAttrs = getFilteredAttributes();
      
      // Collect unique option keys that need fetching
      const optionKeysToFetch: string[] = [];
      filteredAttrs.forEach(attr => {
        if (typeof attr.options === 'string') {
          const optionKey = attr.options;
          // Only fetch if not already fetched or being fetched (using ref for immediate check)
          if (!fetchedOrFetchingOptions.current.has(optionKey)) {
            optionKeysToFetch.push(optionKey);
            // Immediately mark as being fetched to prevent duplicate requests
            fetchedOrFetchingOptions.current.add(optionKey);
          }
        }
      });
      
      if (optionKeysToFetch.length === 0) return;
      
      // Set loading state for relevant fields
      const fieldsLoading: Record<string, boolean> = {};
      filteredAttrs.forEach(attr => {
        if (typeof attr.options === 'string' && optionKeysToFetch.includes(attr.options)) {
          fieldsLoading[attr.name] = true;
        }
      });
      setLoadingOptions(prev => ({ ...prev, ...fieldsLoading }));
      
      // Fetch all options in parallel
      const fetchPromises = optionKeysToFetch.map(async (optionKey) => {
        try {
          // Resolve {instanceId} placeholder if present
          const apiPath = resolveApiPath(optionKey);
          const response = await api.get(apiPath);
          
          let fetchedOptions: Array<{ value: string | number; label: string }> = [];
          
          if (Array.isArray(response.data)) {
            // Backend returns standardized format: [{ value, label }]
            fetchedOptions = response.data.map((opt: any) => {
              if (typeof opt === 'string' || typeof opt === 'number') {
                return { value: opt, label: String(opt) };
              }
              // Handle multilingual labels
              const labelValue = typeof opt.label === 'string' 
                ? opt.label 
                : opt.label?.en || opt.label?.[Object.keys(opt.label || {})[0]] || String(opt.value);
              return { value: opt.value, label: labelValue };
            });
          }
          
          return { key: optionKey, options: fetchedOptions, error: null };
        } catch (error: any) {
          console.error(`Failed to fetch options for ${optionKey}:`, error);
          return { key: optionKey, options: [], error };
        }
      });
      
      // Wait for all fetches to complete
      const results = await Promise.all(fetchPromises);
      
      // Update cache with all results at once
      setOptionsCache(prev => {
        const newCache = { ...prev };
        results.forEach(({ key, options }) => {
          newCache[key] = options;
        });
        return newCache;
      });
      
      // Clear loading states
      const fieldsNotLoading: Record<string, boolean> = {};
      filteredAttrs.forEach(attr => {
        if (typeof attr.options === 'string' && optionKeysToFetch.includes(attr.options)) {
          fieldsNotLoading[attr.name] = false;
        }
      });
      setLoadingOptions(prev => ({ ...prev, ...fieldsNotLoading }));
    };
    
    fetchOptions();
  }, [getFilteredAttributes, resolveApiPath]);

  // Handle field focus
  const handleFieldFocus = (fieldName: string, focused: boolean) => {
    setFieldFocused(prev => ({
      ...prev,
      [fieldName]: focused
    }));
  };

  // Handle field value changes
  // For timestamp fields: Convert datetime-local string to Unix timestamp (float in seconds)
  const handleFieldChange = (fieldName: string, value: any, fieldType?: AttributeType) => {
    let processedValue = value;
    
    // If field type is timestamp, convert datetime-local string to Unix timestamp
    if (fieldType === 'timestamp' && typeof value === 'string' && value) {
      const date = new Date(value);
      if (!isNaN(date.getTime())) {
        // Convert to Unix timestamp in seconds (float)
        processedValue = date.getTime() / 1000;
      }
    }
    
    setFormData(prev => ({
      ...prev,
      [fieldName]: processedValue
    }));

    // Clear error for this field when user starts typing
    if (errors[fieldName]) {
      setErrors(prev => {
        const newErrors = { ...prev };
        delete newErrors[fieldName];
        return newErrors;
      });
    }
  };
  
  // Convert Unix timestamp (seconds) to datetime-local input format
  const timestampToDatetimeLocal = (timestamp: number | string | null | undefined): string => {
    if (timestamp === null || timestamp === undefined || timestamp === '') {
      return '';
    }
    const numValue = typeof timestamp === 'string' ? parseFloat(timestamp) : timestamp;
    if (isNaN(numValue)) {
      return '';
    }
    // Unix timestamp in seconds - convert to milliseconds for Date
    const date = new Date(numValue * 1000);
    if (isNaN(date.getTime())) {
      return '';
    }
    // Format as datetime-local: YYYY-MM-DDTHH:mm
    return date.toISOString().slice(0, 16);
  };

  // Normalize options for a field
  const normalizeOptions = (attr: AttributeDefinition): Array<{ value: string | number; label: string }> => {
    // Check if optionsReference is provided and cached
    if (typeof attr.options === 'string' && optionsCache[attr.options]) {
      return optionsCache[attr.options];
    }

    // Handle direct options array
    if (Array.isArray(attr.options)) {
      return attr.options.map(opt => {
        if (typeof opt === 'string') {
          return { value: opt, label: opt };
        }
        if (typeof opt === 'object' && 'value' in opt) {
          const labelValue = typeof opt.label === 'string' 
            ? opt.label 
            : opt.label?.en || opt.label?.[Object.keys(opt.label || {})[0]] || String(opt.value);
          return {
            value: opt.value,
            label: labelValue
          };
        }
        return { value: String(opt), label: String(opt) };
      });
    }

    return [];
  };

  // Validate all fields
  const validateFields = (): boolean => {
    const newErrors: Record<string, string> = {};
    const filteredAttrs = getFilteredAttributes();

    filteredAttrs.forEach(attr => {
      const value = formData[attr.name];

      // Check required fields
      if (attr.required) {
        // Special handling for TextMultilingual fields (by explicit type only)
        const isMultilingualField = isMultilingualType(attr.type as AttributeType);
        if (isMultilingualField && isTextMultilingual(value)) {
          if (!value.en || typeof value.en !== 'string' || value.en.trim() === '') {
            newErrors[attr.name] = t('formgen.form.required', `${attr.label} (English) is required`);
            return;
          }
        } else if (value === undefined || value === null || value === '' || 
            (Array.isArray(value) && value.length === 0)) {
          newErrors[attr.name] = t('formgen.form.required', `${attr.label} is required`);
          return;
        }
      }

      // Type-specific validation
      if (value !== undefined && value !== null && value !== '') {
        // Integer validation
        if (attr.type === 'integer') {
          if (!Number.isInteger(Number(value)) || isNaN(Number(value))) {
            newErrors[attr.name] = t('formgen.form.invalidInteger', `${attr.label} must be a valid integer`);
            return;
          }
        }

        // Number/Float validation
        if (isNumberType(attr.type)) {
          if (isNaN(Number(value))) {
            newErrors[attr.name] = t('formgen.form.invalidNumber', `${attr.label} must be a valid number`);
            return;
          }
        }

        // Email validation
        if (attr.type === 'email') {
          if (!/\S+@\S+\.\S+/.test(String(value))) {
            newErrors[attr.name] = t('formgen.form.invalidEmail', 'Invalid email format');
            return;
          }
        }

        // URL validation
        if (attr.type === 'url') {
          try {
            new URL(String(value));
          } catch {
            newErrors[attr.name] = t('formgen.form.invalidUrl', 'Invalid URL format');
            return;
          }
        }

        // Select/Multiselect option validation
        if (isSelectType(attr.type)) {
          const options = normalizeOptions(attr);
          if (options.length > 0 && !options.some(opt => String(opt.value) === String(value))) {
            newErrors[attr.name] = t('formgen.form.invalidOption', 'Invalid option selected');
            return;
          }
        }

        // Timestamp/Date validation
        if (isDateTimeType(attr.type)) {
          // For timestamp fields, value is stored as Unix timestamp (float)
          // For date/time fields, value is stored as string
          let isValid = false;
          if (attr.type === 'timestamp' && typeof value === 'number') {
            // Unix timestamp in seconds - valid if it's a reasonable timestamp
            isValid = value > 0 && value < 4102444800; // Before year 2100
          } else {
            const dateValue = new Date(String(value));
            isValid = !isNaN(dateValue.getTime());
          }
          if (!isValid) {
            newErrors[attr.name] = t('formgen.form.invalidDate', 'Invalid date format');
            return;
          }
        }

        // Custom validation from attribute
        if (attr.validation && typeof attr.validation === 'function') {
          const error = attr.validation(value);
          if (error) {
            newErrors[attr.name] = error;
            return;
          }
        }
      }
    });

    // Apply custom validator if provided
    if (customValidator) {
      const customErrors = customValidator(formData, filteredAttrs);
      Object.assign(newErrors, customErrors);
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  // Handle form submission
  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    
    if (!validateFields()) {
      return;
    }

    // Prepare form data - ensure roleLabel is a string if it exists
    const preparedFormData = { ...formData };
    
    // Ensure roleLabel is a string (not object/array/null/undefined)
    if ('roleLabel' in preparedFormData) {
      const roleLabelValue = (preparedFormData as any).roleLabel;
      if (typeof roleLabelValue !== 'string') {
        // Convert to string if it's not already
        if (roleLabelValue === null || roleLabelValue === undefined) {
          // Remove if null/undefined - let validation handle it
          delete (preparedFormData as any).roleLabel;
        } else if (typeof roleLabelValue === 'object') {
          // If it's an object, try to extract a string value or remove it
          console.warn('⚠️ roleLabel is an object, removing it:', roleLabelValue);
          delete (preparedFormData as any).roleLabel;
        } else {
          // Convert to string
          (preparedFormData as any).roleLabel = String(roleLabelValue);
        }
      }
    }
    
    console.log('📤 FormGeneratorForm - handleSubmit - Complete formData structure:', {
      originalFormData: formData,
      preparedFormData: preparedFormData,
      formDataKeys: Object.keys(preparedFormData),
      formDataEntries: Object.entries(preparedFormData).map(([key, value]) => ({
        key,
        value,
        valueType: typeof value,
        valueIsObject: typeof value === 'object' && value !== null && !Array.isArray(value),
        valueIsArray: Array.isArray(value),
        valueIsNull: value === null,
        valueIsUndefined: value === undefined,
        valueStringified: typeof value === 'object' ? JSON.stringify(value, null, 2) : String(value)
      })),
      formDataStringified: JSON.stringify(preparedFormData, null, 2),
      formDataStringifiedCompact: JSON.stringify(preparedFormData),
      hasRoleLabel: 'roleLabel' in preparedFormData,
      roleLabelValue: (preparedFormData as any).roleLabel,
      roleLabelType: typeof (preparedFormData as any).roleLabel,
      roleLabelIsString: typeof (preparedFormData as any).roleLabel === 'string'
    });

    try {
      setSubmitting(true);
      await onSubmit(preparedFormData);
    } catch (error: any) {
      console.error('Form submission error:', error);
      // Handle backend validation errors
      if (error.response?.data?.errors) {
        setErrors(error.response.data.errors);
      }
    } finally {
      setSubmitting(false);
    }
  };

  // Handle cancel
  const handleCancel = () => {
    if (data) {
      setFormData({ ...data });
    }
    setErrors({});
    onCancel?.();
  };

  // Helper function to get label class
  const getLabelClass = (fieldName: string, value: any) => {
    const isFocused = fieldFocused[fieldName];
    const hasValue = value !== undefined && value !== null && value !== '' && 
                     !(Array.isArray(value) && value.length === 0);
    
    if (isFocused) {
      return styles.activeFocusedLabel;
    } else if (hasValue) {
      return styles.focusedLabel;
    } else {
      return styles.label;
    }
  };

  // Render multilingual field
  const renderMultilingualField = (attr: AttributeDefinition) => {
    const value = formData[attr.name] || { en: '' };
    const hasError = errors[attr.name];
    const isReadonly = mode === 'display' || attr.readonly || attr.editable === false;
    
    // Ensure value is a TextMultilingual object
    const multilingualValue = isTextMultilingual(value) ? value : { en: typeof value === 'string' ? value : '' };
    
    const languages = [
      { code: 'en', label: 'English', required: true },
      { code: 'ge', label: 'German', required: false },
      { code: 'fr', label: 'French', required: false },
      { code: 'it', label: 'Italian', required: false }
    ];
    
    const handleMultilingualChange = (langCode: string, langValue: string) => {
      const newValue = { ...multilingualValue, [langCode]: langValue };
      handleFieldChange(attr.name, newValue);
    };
    
    if (isReadonly) {
      // Display mode - show all languages
      const displayValues = languages
        .filter(lang => multilingualValue[lang.code] && multilingualValue[lang.code].trim())
        .map(lang => `${lang.label}: ${multilingualValue[lang.code]}`)
        .join(' | ');
      
      return (
        <div className={styles.fieldGroup} key={attr.name}>
          <div className={styles.readonlyField}>
            {displayValues || t('common.na', 'N/A')}
          </div>
          <label className={styles.focusedLabel}>
            {attr.label}
          </label>
        </div>
      );
    }
    
    return (
      <div className={styles.fieldGroup} key={attr.name}>
        <label className={styles.fieldLabel}>
          {attr.label}
          {attr.required && <span className={styles.required}>*</span>}
        </label>
        {languages.map(lang => (
          <div className={styles.floatingLabelInput} key={lang.code}>
            <input
              type="text"
              value={multilingualValue[lang.code] || ''}
              onChange={(e) => handleMultilingualChange(lang.code, e.target.value)}
              onFocus={() => handleFieldFocus(`${attr.name}.${lang.code}`, true)}
              onBlur={() => handleFieldFocus(`${attr.name}.${lang.code}`, false)}
              className={`${styles.fieldInput} ${hasError && lang.code === 'en' ? styles.fieldError : ''}`}
            />
            <label className={getLabelClass(`${attr.name}.${lang.code}`, multilingualValue[lang.code])}>
              {lang.label}
              {lang.required && <span className={styles.required}>*</span>}
            </label>
          </div>
        ))}
        {hasError && <span className={styles.errorText}>{hasError}</span>}
      </div>
    );
  };

  // Render field based on attribute type
  const renderField = (attr: AttributeDefinition) => {
    const value = formData[attr.name];
    const hasError = errors[attr.name];
    const isReadonly = mode === 'display' || attr.readonly || attr.editable === false;
    
    // Check if this is a multilingual field - by explicit type ONLY
    const shouldRenderAsMultilingual = isMultilingualType(attr.type as AttributeType) && 
        (isTextMultilingual(value) || value === undefined || value === null || value === '');
    if (shouldRenderAsMultilingual) {
      return renderMultilingualField(attr);
    }

    // Readonly/Display field
    if (isReadonly) {
      let displayValue = value;
      if (isCheckboxType(attr.type)) {
        displayValue = value ? t('common.yes', 'Yes') : t('common.no', 'No');
      } else if (isSelectType(attr.type)) {
        const options = normalizeOptions(attr);
        const selectedOption = options.find(opt => String(opt.value) === String(value));
        displayValue = selectedOption ? selectedOption.label : value;
      } else if (isMultiselectType(attr.type)) {
        const options = normalizeOptions(attr);
        const selectedValues = Array.isArray(value) ? value : (value ? [value] : []);
        displayValue = selectedValues.map(v => {
          const option = options.find(opt => String(opt.value) === String(v));
          return option ? option.label : v;
        }).join(', ') || t('common.none', 'None');
      } else if (typeof value === 'object' && value !== null) {
        // Convert objects/arrays to formatted JSON string for display
        displayValue = JSON.stringify(value, null, 2);
      }

      // Use pre tag for JSON/object values to preserve formatting
      const isJsonValue = typeof value === 'object' && value !== null;
      
      return (
        <div className={styles.floatingLabelInput} key={attr.name}>
          <div className={styles.readonlyField} style={isJsonValue ? { whiteSpace: 'pre-wrap', fontFamily: 'monospace', fontSize: '0.85em' } : undefined}>
            {displayValue || t('common.na', 'N/A')}
          </div>
          <label className={styles.focusedLabel}>
            {attr.label}
          </label>
        </div>
      );
    }

    // Select/Enum field
    if (isSelectType(attr.type)) {
      const options = normalizeOptions(attr);
      const isLoading = typeof attr.options === 'string' && loadingOptions[attr.name];

      return (
        <div className={styles.floatingLabelInput} key={attr.name}>
          <select
            value={value || ''}
            onChange={(e) => handleFieldChange(attr.name, e.target.value)}
            onFocus={() => handleFieldFocus(attr.name, true)}
            onBlur={() => handleFieldFocus(attr.name, false)}
            className={`${styles.fieldInput} ${hasError ? styles.fieldError : ''}`}
            disabled={isLoading}
          >
            <option value="" disabled hidden></option>
            {options.map(option => (
              <option key={option.value} value={option.value}>{option.label}</option>
            ))}
          </select>
          <label className={getLabelClass(attr.name, value)}>
            {attr.label}
            {attr.required && <span className={styles.required}>*</span>}
          </label>
          {hasError && <span className={styles.errorText}>{hasError}</span>}
        </div>
      );
    }

    // Multiselect field
    if (isMultiselectType(attr.type)) {
      const options = normalizeOptions(attr);
      const currentValues = Array.isArray(value) ? value : (value ? [value] : []);
      const isLoading = typeof attr.options === 'string' && loadingOptions[attr.name];

      return (
        <div className={styles.fieldGroup} key={attr.name}>
          <label className={styles.fieldLabel}>
            {attr.label}
            {attr.required && <span className={styles.required}>*</span>}
            {currentValues.length > 0 && (
              <span className={styles.multiselectCount}> ({currentValues.length} {t('common.selected', 'selected')})</span>
            )}
          </label>
          <div className={`${styles.multiselectContainer} ${hasError ? styles.fieldError : ''}`}>
            {isLoading ? (
              <div className={styles.multiselectLoading}>{t('common.loading', 'Loading options...')}</div>
            ) : options.length === 0 ? (
              <div className={styles.multiselectEmpty}>{t('common.noOptions', 'No options available')}</div>
            ) : (
              <div className={styles.multiselectOptions}>
                {options.map(option => {
                  const isSelected = currentValues.some(v => String(v) === String(option.value));
                  return (
                    <label key={option.value} className={styles.multiselectOption}>
                      <input
                        type="checkbox"
                        checked={isSelected}
                        onChange={(e) => {
                          let newValues: any[];
                          if (e.target.checked) {
                            newValues = [...currentValues, option.value];
                          } else {
                            newValues = currentValues.filter(v => String(v) !== String(option.value));
                          }
                          handleFieldChange(attr.name, newValues);
                        }}
                        onFocus={() => handleFieldFocus(attr.name, true)}
                        onBlur={() => handleFieldFocus(attr.name, false)}
                        className={styles.multiselectCheckbox}
                      />
                      <span className={styles.multiselectLabel}>{option.label}</span>
                    </label>
                  );
                })}
              </div>
            )}
          </div>
          {hasError && <span className={styles.errorText}>{hasError}</span>}
        </div>
      );
    }

    // Checkbox/Boolean field
    if (isCheckboxType(attr.type)) {
      return (
        <div className={styles.fieldGroup} key={attr.name}>
          <label className={styles.checkboxLabel}>
            <input
              type="checkbox"
              checked={!!value}
              onChange={(e) => handleFieldChange(attr.name, e.target.checked)}
              onFocus={() => handleFieldFocus(attr.name, true)}
              onBlur={() => handleFieldFocus(attr.name, false)}
              className={styles.checkboxInput}
            />
            {attr.label}
            {attr.required && <span className={styles.required}>*</span>}
          </label>
          {hasError && <span className={styles.errorText}>{hasError}</span>}
        </div>
      );
    }

    // Textarea field
    if (isTextareaType(attr.type)) {
      const minRows = attr.minRows || 4;
      const maxRows = attr.maxRows || 8;
      const minHeight = minRows * 1.5 * 16;
      const maxHeight = maxRows * 1.5 * 16;
      
      // Handle object/array values by converting to JSON string for display
      const isObjectValue = typeof value === 'object' && value !== null;
      // Check if string value looks like JSON (for fields that were originally objects but temporarily invalid)
      const looksLikeJson = typeof value === 'string' && value.trim().match(/^[\[{]/);
      const isJsonField = isObjectValue || looksLikeJson;
      
      let currentValue = '';
      if (isObjectValue) {
        try {
          currentValue = JSON.stringify(value, null, 2);
        } catch {
          currentValue = String(value);
        }
      } else {
        currentValue = value || '';
      }
      
      const isContentField = attr.name === 'content' || attr.name.toLowerCase().includes('content');
      const textareaClassName = isContentField 
        ? `${styles.fieldTextarea} ${styles.contentTextarea} ${hasError ? styles.fieldError : ''}`
        : `${styles.fieldTextarea} ${hasError ? styles.fieldError : ''}`;
      
      return (
        <div className={styles.floatingLabelInput} key={attr.name}>
          <textarea
            name={attr.name}
            value={currentValue}
            onChange={(e) => {
              const newTextValue = e.target.value;
              const trimmed = newTextValue.trim();
              // Try to parse as JSON if it looks like JSON (starts with { or [)
              if (trimmed.match(/^[\[{]/)) {
                try {
                  const parsed = JSON.parse(newTextValue);
                  handleFieldChange(attr.name, parsed);
                } catch {
                  // If parsing fails, store as string (user is still typing)
                  handleFieldChange(attr.name, newTextValue);
                }
              } else {
                handleFieldChange(attr.name, newTextValue);
              }
              const textarea = e.target;
              textarea.style.height = 'auto';
              const scrollHeight = textarea.scrollHeight;
              const newHeight = Math.max(
                minHeight,
                Math.min(scrollHeight || minHeight, maxHeight)
              );
              textarea.style.height = `${newHeight}px`;
            }}
            onFocus={() => handleFieldFocus(attr.name, true)}
            onBlur={() => handleFieldFocus(attr.name, false)}
            className={textareaClassName}
            rows={minRows}
            style={isJsonField ? { fontFamily: 'monospace', fontSize: '0.85em' } : undefined}
            ref={(textarea) => {
              if (textarea) {
                textarea.style.setProperty('min-height', `${minHeight}px`, 'important');
                textarea.style.setProperty('height', `${minHeight}px`, 'important');
                textarea.style.setProperty('max-height', `${maxHeight}px`, 'important');
                textarea.setAttribute('rows', minRows.toString());
              }
            }}
          />
          <label className={getLabelClass(attr.name, currentValue)}>
            {attr.label}
            {attr.required && <span className={styles.required}>*</span>}
          </label>
          {hasError && <span className={styles.errorText}>{hasError}</span>}
        </div>
      );
    }

    // File field
    if (isFileType(attr.type)) {
      return (
        <div className={styles.floatingLabelInput} key={attr.name}>
          <input
            type="file"
            onChange={(e) => {
              const file = e.target.files?.[0];
              handleFieldChange(attr.name, file);
            }}
            onFocus={() => handleFieldFocus(attr.name, true)}
            onBlur={() => handleFieldFocus(attr.name, false)}
            className={`${styles.fieldInput} ${hasError ? styles.fieldError : ''}`}
          />
          <label className={getLabelClass(attr.name, value)}>
            {attr.label}
            {attr.required && <span className={styles.required}>*</span>}
          </label>
          {hasError && <span className={styles.errorText}>{hasError}</span>}
        </div>
      );
    }

    // Default input field (text, email, date, time, url, password, number, integer, float, timestamp)
    const inputType = attributeTypeToInputType(attr.type);
    
    // For timestamp fields, convert Unix timestamp (float) to datetime-local format for display
    const displayValue = attr.type === 'timestamp' 
      ? timestampToDatetimeLocal(value)
      : (value || '');

    return (
      <div className={styles.floatingLabelInput} key={attr.name}>
        <input
          type={inputType}
          value={displayValue}
          onChange={(e) => {
            let newValue: any = e.target.value;
            if (isNumberType(attr.type)) {
              newValue = e.target.value === '' ? '' : Number(e.target.value);
            }
            // Pass field type for timestamp conversion
            handleFieldChange(attr.name, newValue, attr.type);
          }}
          onFocus={() => handleFieldFocus(attr.name, true)}
          onBlur={() => handleFieldFocus(attr.name, false)}
          className={`${styles.fieldInput} ${hasError ? styles.fieldError : ''}`}
        />
        <label className={getLabelClass(attr.name, displayValue)}>
          {attr.label}
          {attr.required && <span className={styles.required}>*</span>}
        </label>
        {hasError && <span className={styles.errorText}>{hasError}</span>}
      </div>
    );
  };

  const filteredAttributes = getFilteredAttributes();

  if (loadingAttributes) {
    return (
      <div className={`${styles.formGeneratorForm} ${className}`}>
        <div className={styles.loadingState}>
          <div className={styles.loadingSpinner}></div>
          <p>{t('common.loading', 'Loading...')}</p>
        </div>
      </div>
    );
  }

  return (
    <div className={`${styles.formGeneratorForm} ${className}`}>
      <form onSubmit={handleSubmit}>
        {filteredAttributes.map(attr => renderField(attr))}
      </form>

      {showButtons && (
        <div className={styles.buttonGroup}>
          {onCancel && (
            <button 
              type="button"
              className={styles.cancelButton}
              onClick={handleCancel}
              disabled={submitting}
            >
              {cancelButtonText || t('common.cancel', 'Cancel')}
            </button>
          )}
          {mode !== 'display' && (
            <button 
              type="button"
              className={styles.submitButton}
              onClick={handleSubmit}
              disabled={submitting}
            >
              {submitting ? t('common.saving', 'Saving...') : (submitButtonText || t('common.save', 'Save'))}
            </button>
          )}
        </div>
      )}
    </div>
  );
}

export default FormGeneratorForm;

