import React from 'react'
import { Field, ErrorType } from '../../../types'
import { AlertCircle, ArrowDown, Wand2, X } from 'lucide-react'
import {
  Tooltip,
  TooltipContent,
  TooltipProvider,
  TooltipTrigger,
} from '@/components/ui/tooltip'
import InputCell from './cells/InputCell'
import SelectCell from './cells/SelectCell'
import MultiSelectCell from './cells/MultiSelectCell'
import { TableCell } from '@/components/ui/table'
import { Skeleton } from '@/components/ui/skeleton'
import { useToast } from '@/hooks/use-toast'
import config from '@/config'

// Context for copy down selection mode
export const CopyDownContext = React.createContext<{
  isInCopyDownMode: boolean;
  sourceRowIndex: number | null;
  sourceFieldKey: string | null;
  targetRowIndex: number | null;
  setIsInCopyDownMode: (value: boolean) => void;
  setSourceRowIndex: (value: number | null) => void;
  setSourceFieldKey: (value: string | null) => void;
  setTargetRowIndex: (value: number | null) => void;
  handleCopyDownComplete: (sourceRowIndex: number, fieldKey: string, targetRowIndex: number) => void;
}>({
  isInCopyDownMode: false,
  sourceRowIndex: null,
  sourceFieldKey: null,
  targetRowIndex: null,
  setIsInCopyDownMode: () => {},
  setSourceRowIndex: () => {},
  setSourceFieldKey: () => {},
  setTargetRowIndex: () => {},
  handleCopyDownComplete: () => {},
});

// Define error object type
type ErrorObject = {
  message: string;
  level: string;
  source?: string;
  type?: ErrorType;
}

// Helper function to check if a value is empty - utility function shared by all components
const isEmpty = (val: any): boolean => 
  val === undefined || 
  val === null || 
  val === '' || 
  (Array.isArray(val) && val.length === 0) ||
  (typeof val === 'object' && !Array.isArray(val) && Object.keys(val).length === 0);

// Memoized validation icon component
const ValidationIcon = React.memo(({ error }: { error: ErrorObject }) => (
  <TooltipProvider>
    <Tooltip delayDuration={200}>
      <TooltipTrigger asChild>
        <div className="cursor-help">
          <AlertCircle className="h-4 w-4 text-red-500" />
        </div>
      </TooltipTrigger>
      <TooltipContent className="max-w-[300px] text-wrap break-words">
        <p>{error.message}</p>
      </TooltipContent>
    </Tooltip>
  </TooltipProvider>
));

ValidationIcon.displayName = 'ValidationIcon';

// Memoized base cell content component
const BaseCellContent = React.memo(({
  field,
  value,
  onChange,
  hasErrors,
  options = [],
  className = '',
  fieldKey = '',
  onStartEdit,
  onEndEdit
}: {
  field: Field<string>;
  value: any;
  onChange: (value: any) => void;
  hasErrors: boolean;
  options?: readonly any[];
  className?: string;
  fieldKey?: string;
  onStartEdit?: () => void;
  onEndEdit?: () => void;
}) => {
  // Get field type information
  const fieldType = fieldKey === 'line' || fieldKey === 'subline' 
    ? 'select'
    : typeof field.fieldType === 'string' 
      ? field.fieldType 
      : field.fieldType?.type || 'input';
  
  // Check for multiline input
  const isMultiline = typeof field.fieldType === 'object' && 
                      (field.fieldType.type === 'input' || field.fieldType.type === 'multi-input') && 
                      field.fieldType.multiline === true;
  
  // Check for price field
  const isPrice = typeof field.fieldType === 'object' && 
                 (field.fieldType.type === 'input' || field.fieldType.type === 'multi-input') && 
                 field.fieldType.price === true;

  // Special case for line and subline - check this first, before any other field type checks
  if (fieldKey === 'line' || fieldKey === 'subline') {
    // Force these fields to always use SelectCell regardless of fieldType
    return (
      <SelectCell
        field={{...field, fieldType: { type: 'select', options }}}
        value={value}
        onChange={onChange}
        onStartEdit={onStartEdit}
        onEndEdit={onEndEdit}
        options={options}
        hasErrors={hasErrors}
        className={className}
        disabled={field.disabled}
      />
    );
  }

  if (fieldType === 'select') {
    return (
      <SelectCell
        field={field}
        value={value}
        onChange={onChange}
        onStartEdit={onStartEdit}
        onEndEdit={onEndEdit}
        options={options}
        hasErrors={hasErrors}
        className={className}
        disabled={field.disabled}
      />
    );
  }

  if (fieldType === 'multi-select' || fieldType === 'multi-input') {
    return (
      <MultiSelectCell
        field={field}
        value={value}
        onChange={onChange}
        onStartEdit={onStartEdit}
        onEndEdit={onEndEdit}
        options={options}
        hasErrors={hasErrors}
        className={className}
        disabled={field.disabled}
      />
    );
  }

  return (
    <InputCell
      field={field}
      value={value}
      onChange={onChange}
      onStartEdit={onStartEdit}
      onEndEdit={onEndEdit}
      hasErrors={hasErrors}
      isMultiline={isMultiline}
      isPrice={isPrice}
      disabled={field.disabled}
    />
  );
}, (prev, next) => {
  // Shallow array comparison for options if arrays
  const optionsEqual = prev.options === next.options || 
    (Array.isArray(prev.options) && Array.isArray(next.options) && 
     prev.options.length === next.options.length &&
     prev.options.every((opt, idx) => opt === (next.options as any[])[idx]));
    
  return (
    prev.value === next.value &&
    prev.hasErrors === next.hasErrors &&
    prev.field === next.field &&
    prev.className === next.className &&
    optionsEqual
  );
});

BaseCellContent.displayName = 'BaseCellContent';

export interface ValidationCellProps {
  field: Field<string>
  value: any
  onChange: (value: any) => void
  errors: ErrorObject[]
  isValidating?: boolean
  fieldKey: string
  options?: readonly any[]
  itemNumber?: string
  width: number
  rowIndex: number
  copyDown?: (endRowIndex?: number) => void
  totalRows?: number
  rowData: Record<string, any>
  editingCells: Set<string>
  setEditingCells: React.Dispatch<React.SetStateAction<Set<string>>>
}

// Add efficient error message extraction function

// Highly optimized error processing function with fast paths for common cases
function processErrors(value: any, errors: ErrorObject[]): {
  hasError: boolean;
  isRequiredButEmpty: boolean;
  shouldShowErrorIcon: boolean;
  errorMessages: string;
} {
  // Fast path - if no errors or empty error array, return immediately
  if (!errors || errors.length === 0) {
    return {
      hasError: false,
      isRequiredButEmpty: false,
      shouldShowErrorIcon: false,
      errorMessages: ''
    };
  }
  
  // Use the shared isEmpty function for value checking
  const valueIsEmpty = isEmpty(value);
  
  // Fast path for the most common case - required field with empty value
  if (valueIsEmpty && errors.length === 1 && errors[0].type === ErrorType.Required) {
    return {
      hasError: true,
      isRequiredButEmpty: true,
      shouldShowErrorIcon: false,
      errorMessages: ''
    };
  }
  
  // For non-empty values with errors, we need to show error icons
  const hasError = errors.some(error => error.level === 'error' || error.level === 'warning');
  
  // For empty values with required errors, show only a border
  const isRequiredButEmpty = valueIsEmpty && errors.some(error => error.type === ErrorType.Required);
  
  // Show error icons for non-empty fields with errors, or for empty fields with non-required errors
  const shouldShowErrorIcon = hasError && (!valueIsEmpty || !errors.every(error => error.type === ErrorType.Required));
  
  // Only compute error messages if we're going to show an icon
  const errorMessages = shouldShowErrorIcon 
    ? errors
        .filter(e => e.level === 'error' || e.level === 'warning')
        .map(e => e.message)
        .join('\n')
    : '';
  
  return {
    hasError,
    isRequiredButEmpty,
    shouldShowErrorIcon,
    errorMessages
  };
}

// Helper function to compare error arrays efficiently with a hash-based approach
function compareErrorArrays(prevErrors: ErrorObject[], nextErrors: ErrorObject[]): boolean {
  // Fast path for referential equality
  if (prevErrors === nextErrors) return true;
  
  // Fast path for length check
  if (!prevErrors || !nextErrors) return prevErrors === nextErrors;
  if (prevErrors.length !== nextErrors.length) return false;
  
  // Generate simple hash from error properties
  const getErrorHash = (error: ErrorObject): string => {
    return `${error.message}|${error.level}|${error.type || ''}`;
  };
  
  // Compare using hashes
  const prevHashes = prevErrors.map(getErrorHash);
  const nextHashes = nextErrors.map(getErrorHash);
  
  // Sort hashes to ensure consistent order
  prevHashes.sort();
  nextHashes.sort();
  
  // Compare sorted hash arrays
  return prevHashes.join(',') === nextHashes.join(',');
}

const ValidationCell = React.memo(({
  field,
  value,
  onChange,
  errors,
  isValidating,
  fieldKey,
  options = [],
  itemNumber,
  width,
  copyDown,
  rowIndex,
  totalRows = 0,
  rowData,
  editingCells,
  setEditingCells
}: ValidationCellProps) => {
  // Use the CopyDown context
  const copyDownContext = React.useContext(CopyDownContext);
  const { toast } = useToast();
  const [isGeneratingUpc, setIsGeneratingUpc] = React.useState(false);
  
  // CRITICAL FIX: For item_number fields, always prioritize the itemNumber prop over the value
  // This ensures that when the itemNumber changes, the display value changes
  let displayValue;
  if (fieldKey === 'item_number' && itemNumber) {
    // Prioritize itemNumber prop for item_number fields
    displayValue = itemNumber;
  } else {
    displayValue = value;
  }
  
  // Use the optimized processErrors function to avoid redundant filtering
  const {
    hasError,
    isRequiredButEmpty,
    shouldShowErrorIcon,
    errorMessages
  } = React.useMemo(() => processErrors(displayValue, errors), [displayValue, errors]);
  
  // Track whether this cell is the source of a copy-down operation
  const isSourceCell = copyDownContext.isInCopyDownMode && 
                       rowIndex === copyDownContext.sourceRowIndex && 
                       fieldKey === copyDownContext.sourceFieldKey;
  
  // Add state for hover on copy down button
  const [isCopyDownHovered, setIsCopyDownHovered] = React.useState(false);
  // Add state for hover on target row
  const [isTargetRowHovered, setIsTargetRowHovered] = React.useState(false);
  
  // PERFORMANCE FIX: Create cell key for editing state management
  const cellKey = `${rowIndex}-${fieldKey}`;
  const isEditingCell = editingCells.has(cellKey);
  
  // SINGLE-CLICK EDITING FIX: Create editing state management functions
  const handleStartEdit = React.useCallback(() => {
    setEditingCells(prev => new Set([...prev, cellKey]));
  }, [setEditingCells, cellKey]);
  
  const handleEndEdit = React.useCallback(() => {
    setEditingCells(prev => {
      const newSet = new Set(prev);
      newSet.delete(cellKey);
      return newSet;
    });
  }, [setEditingCells, cellKey]);
  
  // Handle copy down button click
  const handleCopyDownClick = React.useCallback(() => {
    if (copyDown && totalRows > rowIndex + 1) {
      // Enter copy down mode
      copyDownContext.setIsInCopyDownMode(true);
      copyDownContext.setSourceRowIndex(rowIndex);
      copyDownContext.setSourceFieldKey(fieldKey);
    }
  }, [copyDown, copyDownContext, fieldKey, rowIndex, totalRows]);
  
  // Check if this cell is in a row that can be a target for copy down
  const isInTargetRow = copyDownContext.isInCopyDownMode && 
                       copyDownContext.sourceFieldKey === fieldKey &&
                       rowIndex > (copyDownContext.sourceRowIndex || 0);
  
  // Check if this row is the currently selected target row
  const isSelectedTarget = isInTargetRow && rowIndex <= (copyDownContext.targetRowIndex || 0);
  
  // Handle click on a potential target cell
  const handleTargetCellClick = React.useCallback(() => {
    if (isInTargetRow && copyDownContext.sourceRowIndex !== null && copyDownContext.sourceFieldKey !== null) {
      copyDownContext.handleCopyDownComplete(
        copyDownContext.sourceRowIndex,
        copyDownContext.sourceFieldKey,
        rowIndex
      );
    }
  }, [copyDownContext, isInTargetRow, rowIndex]);
  
  // Memoize the cell style objects to avoid recreating them on every render
  const cellStyle = React.useMemo(() => ({
    width: `${width}px`, 
    minWidth: `${width}px`, 
    maxWidth: `${width}px`, 
    boxSizing: 'border-box' as const,
    cursor: isInTargetRow ? 'pointer' : undefined
  }), [width, isInTargetRow]);
  
  // Memoize the cell class name to prevent re-calculating on every render
  const cellClassName = React.useMemo(() => {
    if (isSourceCell || isSelectedTarget || isInTargetRow) {
      return isSourceCell ? '!bg-blue-100 !border-blue-500 !rounded-md' : 
            isSelectedTarget ? '!bg-blue-200 !border-blue-200 !rounded-md' : 
            isInTargetRow ? 'hover:!bg-blue-100 !border-blue-200 !rounded-md' : '';
    }
    return '';
  }, [isSourceCell, isSelectedTarget, isInTargetRow]);

  const isUpcField = fieldKey === 'upc';
  const baseIsLoading = isValidating === true;
  const showGeneratingSkeleton = isUpcField && isGeneratingUpc;
  const isLoading = baseIsLoading || showGeneratingSkeleton;

  const supplierRaw = rowData?.supplier ?? rowData?.supplier_id ?? rowData?.supplierId;
  const supplierIdString = supplierRaw !== undefined && supplierRaw !== null
    ? String(supplierRaw).trim()
    : '';
  const normalizedSupplierId = /^\d+$/.test(supplierIdString) ? supplierIdString : '';
  const canGenerateUpc = normalizedSupplierId !== '';
  const upcValueEmpty = isUpcField && isEmpty(displayValue);
  const showGenerateButton = upcValueEmpty && !isEditingCell && !copyDownContext.isInCopyDownMode && !isInTargetRow && !isLoading;
  const cellClassNameWithPadding = showGenerateButton ? `${cellClassName} pr-10`.trim() : cellClassName;
  const buttonDisabled = !canGenerateUpc || isGeneratingUpc;
  const tooltipMessage = canGenerateUpc ? 'Generate UPC' : 'Select a supplier before generating a UPC';

  const handleGenerateUpc = React.useCallback(async () => {
    if (!normalizedSupplierId) {
      toast({
        variant: 'destructive',
        description: 'Select a supplier before generating a UPC.',
      });
      return;
    }

    if (isGeneratingUpc) {
      return;
    }

    setIsGeneratingUpc(true);

    try {
      const response = await fetch(`${config.apiUrl}/import/generate-upc`, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ supplierId: normalizedSupplierId })
      });

      let payload = null;
      try {
        payload = await response.json();
      } catch (parseError) {
        // Ignore JSON parse errors and handle via status code
      }

      if (!response.ok) {
        const message = payload?.error || `Request failed (${response.status})`;
        throw new Error(message);
      }

      if (!payload || !payload.success || !payload.upc) {
        throw new Error(payload?.error || 'Unexpected response while generating UPC');
      }

      onChange(payload.upc);
    } catch (error) {
      console.error('Error generating UPC:', error);
      const errorMessage =
        typeof error === 'object' &&
        error !== null &&
        'message' in error &&
        typeof (error as { message?: unknown }).message === 'string'
          ? (error as { message: string }).message
          : 'Failed to generate UPC';
      toast({
        variant: 'destructive',
        description: errorMessage,
      });
    } finally {
      setIsGeneratingUpc(false);
    }
  }, [normalizedSupplierId, isGeneratingUpc, onChange, toast]);

  const handleGenerateButtonClick = React.useCallback((event: React.MouseEvent<HTMLButtonElement>) => {
    event.preventDefault();
    event.stopPropagation();
    if (!buttonDisabled) {
      handleGenerateUpc();
    }
  }, [buttonDisabled, handleGenerateUpc]);
  const containerClassName = `truncate overflow-hidden${isCopyDownHovered && !copyDownContext.isInCopyDownMode ? ' bg-blue-50/50' : ''}${showGenerateButton ? ' relative group/upc' : ''}`.trim();

  return (
    <TableCell 
      className="p-1 group relative"
      style={cellStyle}
      onClick={isInTargetRow ? handleTargetCellClick : undefined}
      onMouseEnter={isInTargetRow ? () => setIsTargetRowHovered(true) : undefined}
      onMouseLeave={isInTargetRow ? () => setIsTargetRowHovered(false) : undefined}
    >
      <div className={`relative ${hasError || isRequiredButEmpty ? 'border-red-500' : ''}`}>
        {shouldShowErrorIcon && !isInTargetRow && (
          <div className="absolute right-1.5 top-1/2 -translate-y-1/2 z-20">
            <ValidationIcon error={{ 
              message: errorMessages, 
              level: 'error',
              type: ErrorType.Custom
            }} />
          </div>
        )}
        {!shouldShowErrorIcon && copyDown && !isEmpty(displayValue) && !copyDownContext.isInCopyDownMode && (
          <div className="absolute right-0.5 top-1/2 -translate-y-1/2 z-20 opacity-0 group-hover:opacity-100 transition-opacity">
            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger asChild>
                  <button 
                    onClick={handleCopyDownClick}
                    onMouseEnter={() => setIsCopyDownHovered(true)}
                    onMouseLeave={() => setIsCopyDownHovered(false)}
                    className="p-1 rounded-full hover:bg-blue-100 text-blue-500/70 hover:text-blue-600 transition-colors"
                    aria-label="Copy value to rows below"
                  >
                    <ArrowDown className="h-3.5 w-3.5" />
                  </button>
                </TooltipTrigger>
                <TooltipContent side="right">
                  <div className="flex flex-col">
                    <p className="font-medium">Copy value to rows below</p>
                  </div>
                </TooltipContent>
              </Tooltip>
            </TooltipProvider>
          </div>
        )}
        {isSourceCell && (
          <div className="absolute right-1.5 top-1/2 -translate-y-1/2 z-20">
            <TooltipProvider>
              <Tooltip>
                <TooltipTrigger asChild>
                  <button 
                    onClick={() => copyDownContext.setIsInCopyDownMode(false)}
                    className="p-1 rounded-full bg-blue-100 text-blue-600 hover:bg-blue-200 transition-colors"
                    aria-label="Cancel copy down"
                  >
                    <X className="h-3.5 w-3.5" />
                  </button>
                </TooltipTrigger>
                <TooltipContent side="right">
                  <p>Cancel copy down</p>
                </TooltipContent>
              </Tooltip>
            </TooltipProvider>
          </div>
        )}
        {isLoading ? (
          <div className={`flex items-center justify-center gap-2 border ${hasError || isRequiredButEmpty ? 'border-red-500' : 'border-input'} rounded-md px-2 py-2`}>
            <Skeleton className="w-full h-4" />
          </div>
        ) : (
          <div 
            className={containerClassName}
            style={{
              backgroundColor: isSourceCell ? '#dbeafe' : 
                              isSelectedTarget ? '#bfdbfe' : 
                              isInTargetRow && isTargetRowHovered ? '#dbeafe' : 
                              undefined,
              borderRadius: (isSourceCell || isSelectedTarget || isInTargetRow) ? '0.375rem' : undefined,
              boxShadow: isSourceCell ? '0 0 0 2px #3b82f6' : undefined
            }}
          >
            <BaseCellContent
              field={field}
              value={displayValue}
              onChange={onChange}
              hasErrors={hasError || isRequiredButEmpty}
              options={options}
              className={cellClassNameWithPadding}
              fieldKey={fieldKey}
              onStartEdit={handleStartEdit}
              onEndEdit={handleEndEdit}
            />
            {showGenerateButton && (
              <TooltipProvider>
                <Tooltip>
                  <TooltipTrigger asChild>
                    <button
                      type="button"
                      onClick={handleGenerateButtonClick}
                      onMouseDown={(event) => event.stopPropagation()}
                      className="absolute right-1 top-1/2 -translate-y-1/2 flex items-center gap-1 rounded-md border border-input bg-background px-2 py-1 text-xs text-muted-foreground shadow-sm transition-opacity opacity-0 group-hover/upc:opacity-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-60"
                      disabled={buttonDisabled}
                      aria-label="Generate UPC"
                    >
                      <Wand2 className="h-3 w-3" />
                    </button>
                  </TooltipTrigger>
                  <TooltipContent side="top">
                    <p>{tooltipMessage}</p>
                  </TooltipContent>
                </Tooltip>
              </TooltipProvider>
            )}
          </div>
        )}
      </div>
    </TableCell>
  );
}, (prevProps, nextProps) => {
  // Fast path: if all props are the same object
  if (prevProps === nextProps) return true;
  
  // Optimize the memo comparison function, checking most impactful props first
  // Check isValidating first as it's most likely to change frequently
  if (prevProps.isValidating !== nextProps.isValidating) return false;
  
  // Then check value changes  
  if (prevProps.value !== nextProps.value) return false;
  
  // Item number is related to validation state
  if (prevProps.itemNumber !== nextProps.itemNumber) return false;
  
  // Check errors with our optimized comparison function
  if (!compareErrorArrays(prevProps.errors, nextProps.errors)) return false;
  
  // Check field identity
  if (prevProps.field !== nextProps.field) return false;
  
  if (prevProps.rowData !== nextProps.rowData) return false;
  if (prevProps.editingCells !== nextProps.editingCells) return false;
  
  // Shallow options comparison - only if field type is select or multi-select
  if (prevProps.field.fieldType?.type === 'select' || prevProps.field.fieldType?.type === 'multi-select') {
    const optionsEqual = prevProps.options === nextProps.options || 
      (Array.isArray(prevProps.options) && 
       Array.isArray(nextProps.options) && 
       prevProps.options.length === nextProps.options.length &&
       prevProps.options.every((opt, idx) => {
         const nextOptions = nextProps.options || [];
         return opt === nextOptions[idx];
       }));
       
    if (!optionsEqual) return false;
  }
  
  // Check copy down context changes
  const copyDownContextChanged = 
    prevProps.rowIndex !== nextProps.rowIndex ||
    prevProps.fieldKey !== nextProps.fieldKey;
    
  if (copyDownContextChanged) return false;
  
  // All essential props are the same - we can skip re-rendering
  return true;
});

ValidationCell.displayName = 'ValidationCell';

export default ValidationCell; 
