import React, { useState, useCallback, useTransition, useRef, useEffect, useMemo } from 'react'
import { Field } from '../../../../types'
import { Input } from '@/components/ui/input'
import { cn } from '@/lib/utils'
import MultilineInput from './MultilineInput'

interface InputCellProps<T extends string> {
  field: Field<T>
  value: any
  onChange: (value: any) => void
  onStartEdit?: () => void
  onEndEdit?: () => void
  hasErrors?: boolean
  isMultiline?: boolean
  isPrice?: boolean
  disabled?: boolean
  className?: string
}

// Add efficient price formatting utility
const formatPrice = (value: string): string => {
  // Remove any non-numeric characters except decimal point
  const numericValue = value.replace(/[^\d.]/g, '');
  
  // Parse as float and format to 2 decimal places
  const numValue = parseFloat(numericValue);
  if (!isNaN(numValue)) {
    return numValue.toFixed(2);
  }
  
  return numericValue;
};

const InputCell = <T extends string>({
  field,
  value,
  onChange,
  onStartEdit,
  onEndEdit,
  hasErrors,
  isMultiline = false,
  isPrice = false,
  disabled = false,
  className = ''
}: InputCellProps<T>) => {
  const [isEditing, setIsEditing] = useState(false);
  const [editValue, setEditValue] = useState('');
  const [isPending, startTransition] = useTransition();
  
  // Use a ref to track if we need to process the value
  const needsProcessingRef = useRef(false);
  
  // Track local display value to avoid waiting for validation
  const [localDisplayValue, setLocalDisplayValue] = useState<string | null>(null);
  
  // Add state for hover
  const [isHovered, setIsHovered] = useState(false);
  
  // Helper function to check if a class is present in the className string
  const hasClass = (cls: string): boolean => {
    const classNames = className.split(' ');
    return classNames.includes(cls);
  };
  
  // Initialize localDisplayValue on mount and when value changes externally
  useEffect(() => {
    if (localDisplayValue === null || 
        (typeof value === 'string' && typeof localDisplayValue === 'string' && 
         value.trim() !== localDisplayValue.trim())) {
      setLocalDisplayValue(value);
    }
  }, [value, localDisplayValue]);
  
  // Efficiently handle price formatting without multiple rerenders
  useEffect(() => {
    if (isPrice && needsProcessingRef.current && !isEditing) {
      needsProcessingRef.current = false;
      
      // Do price processing only when needed
      const formattedValue = formatPrice(value);
      if (formattedValue !== value) {
        onChange(formattedValue);
      }
    }
  }, [value, isPrice, isEditing, onChange]);
  
  // Handle focus event - optimized to be synchronous
  const handleFocus = useCallback(() => {
    setIsEditing(true);
    
    // For price fields, strip formatting when focusing
    if (value !== undefined && value !== null) {
      if (isPrice) {
        // Remove any non-numeric characters except decimal point
        const numericValue = String(value).replace(/[^\d.]/g, '');
        setEditValue(numericValue);
      } else {
        setEditValue(String(value));
      }
    } else {
      setEditValue('');
    }
    
    onStartEdit?.();
  }, [value, onStartEdit, isPrice]);
  
  // Handle blur event - use transition for non-critical updates
  const handleBlur = useCallback(() => {
    // First - lock in the current edit value to prevent it from being lost
    const finalValue = editValue.trim();
    
    // Then transition to non-editing state
    startTransition(() => {
      setIsEditing(false);
      
      // Format the value for storage (remove formatting like $ for price)
      let processedValue = finalValue;
      
      if (isPrice && processedValue) {
        needsProcessingRef.current = true;
      }
      
      // Update local display value immediately to prevent UI flicker
      setLocalDisplayValue(processedValue);
      
      // Commit the change to parent component
      onChange(processedValue);
      onEndEdit?.();
    });
  }, [editValue, onChange, onEndEdit, isPrice]);
  
  // Handle direct input change - optimized to be synchronous for typing
  const handleChange = useCallback((e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => {
    const newValue = isPrice ? e.target.value.replace(/[$,]/g, '') : e.target.value;
    setEditValue(newValue);
  }, [isPrice]);
  
  // Get the display value - prioritize local display value
  const displayValue = useMemo(() => {
    // First priority: local display value (for immediate updates)
    if (localDisplayValue !== null) {
      if (isPrice) {
        // Format price value
        const numValue = parseFloat(localDisplayValue);
        return !isNaN(numValue) ? numValue.toFixed(2) : localDisplayValue;
      }
      return localDisplayValue;
    }
    
    // Second priority: handle price formatting for the actual value
    if (isPrice && value) {
      if (typeof value === 'number') {
        return value.toFixed(2);
      } else if (typeof value === 'string' && /^-?\d+(\.\d+)?$/.test(value)) {
        return parseFloat(value).toFixed(2);
      }
    }
    
    // Default: use the actual value or empty string
    return value ?? '';
  }, [isPrice, value, localDisplayValue]);
  
  // Add outline even when not in focus
  const outlineClass = "border focus-visible:ring-0 focus-visible:ring-offset-0";
  
  // If disabled, just render the value without any interactivity
  if (disabled) {
    return (
      <div 
        className={cn(
          "px-3 py-2 h-10 rounded-md text-sm w-full",
          outlineClass,
          hasErrors ? "border-destructive" : "border-input"
        )}
        style={{
          backgroundColor: hasClass('!bg-blue-100') ? '#dbeafe' : 
                          hasClass('!bg-blue-200') ? '#bfdbfe' : 
                          hasClass('hover:!bg-blue-100') && isHovered ? '#dbeafe' :
                          undefined,
          borderColor: hasClass('!border-blue-500') ? '#3b82f6' : 
                      hasClass('!border-blue-200') ? '#bfdbfe' : 
                      hasClass('!border-blue-200') && isHovered ? '#bfdbfe' :
                      undefined,
          borderRadius: hasClass('!rounded-md') ? '0.375rem' : undefined,
          borderWidth: hasClass('!border-blue-500') || hasClass('!border-blue-200') ? '0px' : undefined,
          cursor: hasClass('hover:!bg-blue-100') ? 'pointer' : undefined
        }}
        onMouseEnter={() => setIsHovered(true)}
        onMouseLeave={() => setIsHovered(false)}
      >
        {displayValue}
      </div>
    );
  }

  // Render multiline fields using the dedicated MultilineInput component
  if (isMultiline) {
    return (
      <MultilineInput
        field={field}
        value={value}
        onChange={onChange}
        hasErrors={hasErrors}
        disabled={disabled}
        className={className}
      />
    );
  }
  
  // Original component for non-multiline fields
  return (
    <div className="w-full">
      {isEditing ? (
        <Input
          type="text"
          value={editValue}
          onChange={handleChange}
          onFocus={handleFocus}
          onBlur={handleBlur}
          autoFocus
          className={cn(
            outlineClass,
            hasErrors ? "border-destructive" : "",
            isPending ? "opacity-50" : "",
            className
          )}
          style={{
            backgroundColor: hasClass('!bg-blue-100') ? '#dbeafe' : 
                            hasClass('!bg-blue-200') ? '#bfdbfe' : 
                            undefined,
            borderColor: hasClass('!border-blue-500') ? '#3b82f6' : 
                        hasClass('!border-blue-200') ? '#bfdbfe' : 
                        undefined,
            borderRadius: hasClass('!rounded-md') ? '0.375rem' : undefined,
            borderWidth: hasClass('!border-blue-500') || hasClass('!border-blue-200') ? '0px' : undefined,
            cursor: hasClass('hover:!bg-blue-100') ? 'pointer' : undefined
          }}
        />
      ) : (
        <div 
          onClick={handleFocus}
          className={cn(
            "px-3 py-2 h-10 rounded-md text-sm w-full cursor-text flex items-center",
            outlineClass,
            hasErrors ? "border-destructive" : "border-input"
          )}
          style={{
            backgroundColor: hasClass('!bg-blue-100') ? '#dbeafe' : 
                            hasClass('!bg-blue-200') ? '#bfdbfe' : 
                            hasClass('hover:!bg-blue-100') && isHovered ? '#dbeafe' :
                            undefined,
            borderColor: hasClass('!border-blue-500') ? '#3b82f6' : 
                        hasClass('!border-blue-200') ? '#bfdbfe' : 
                        hasClass('!border-blue-200') && isHovered ? '#bfdbfe' :
                        undefined,
            borderRadius: hasClass('!rounded-md') ? '0.375rem' : undefined,
            borderWidth: hasClass('!border-blue-500') || hasClass('!border-blue-200') ? '0px' : undefined,
            cursor: hasClass('hover:!bg-blue-100') ? 'pointer' : 'text'
          }}
          onMouseEnter={() => setIsHovered(true)}
          onMouseLeave={() => setIsHovered(false)}
        >
          {displayValue}
        </div>
      )}
    </div>
  )
}

// Optimize memo comparison to focus on essential props
export default React.memo(InputCell, (prev, next) => {
  if (prev.hasErrors !== next.hasErrors) return false;
  if (prev.isMultiline !== next.isMultiline) return false;
  if (prev.isPrice !== next.isPrice) return false;
  if (prev.disabled !== next.disabled) return false;
  if (prev.field !== next.field) return false;
  
  // Only check value if not editing (to avoid expensive rerender during editing)
  if (prev.value !== next.value) {
    // For price values, do a more intelligent comparison
    if (prev.isPrice) {
      // Convert both to numeric values for comparison
      const prevNum = typeof prev.value === 'number' ? prev.value : 
                    typeof prev.value === 'string' ? parseFloat(prev.value) : 0;
      const nextNum = typeof next.value === 'number' ? next.value : 
                    typeof next.value === 'string' ? parseFloat(next.value) : 0;
                    
      // Only update if the actual numeric values differ
      if (!isNaN(prevNum) && !isNaN(nextNum) && 
          Math.abs(prevNum - nextNum) > 0.001) {
        return false;
      }
    } else {
      return false;
    }
  }
  
  return true;
}); 