import { useCallback } from 'react'
import type { Field, Fields, RowHook } from '../../../types'
import { ErrorSources } from '../../../types'
import { RowData, InfoWithSource } from './validationTypes'
import { useFieldValidation, clearValidationCacheForField, clearAllUniquenessCaches } from './useFieldValidation'
import { useUniqueValidation } from './useUniqueValidation'

// Main validation hook that brings together field and uniqueness validation
export const useValidation = <T extends string>(
  fields: Fields<T>,
  rowHook?: RowHook<T>
) => {
  // Use the field validation hook
  const { validateField, validateRow } = useFieldValidation(fields, rowHook);
  
  // Use the uniqueness validation hook
  const {
    validateUniqueField,
    validateAllUniqueFields
  } = useUniqueValidation(fields);

  // Run complete validation
  const validateData = useCallback(async (data: RowData<T>[], fieldToUpdate?: { rowIndex: number, fieldKey: string }) => {
    const validationErrors = new Map<number, Record<string, InfoWithSource>>();
    
    // If we're updating a specific field, only validate that field for that row
    if (fieldToUpdate) {
      const { rowIndex, fieldKey } = fieldToUpdate;
      
      // Special handling for fields that often update item_number
      const triggersItemNumberValidation = fieldKey === 'upc' || fieldKey === 'barcode' || fieldKey === 'supplier';
      
      // If updating a uniqueness field or field that affects item_number, clear ALL related validation caches
      const isUniqueField = fieldKey === 'upc' || fieldKey === 'item_number' || 
                           fieldKey === 'supplier_no' || fieldKey === 'notions_no' || 
                           fieldKey === 'name' || triggersItemNumberValidation;
      
      // Force cache clearing for uniqueness-validated fields to ensure fresh validation
      if (isUniqueField) {
        console.log(`Clearing validation cache for uniqueness field: ${fieldKey}`);
        clearValidationCacheForField(fieldKey);
        
        // If a field that might affect item_number, also clear item_number cache
        if (triggersItemNumberValidation) {
          console.log('Also clearing item_number validation cache');
          clearValidationCacheForField('item_number');
        }
      }
      
      if (rowIndex >= 0 && rowIndex < data.length) {
        const row = data[rowIndex];
        
        // Find the field definition
        const field = fields.find(f => String(f.key) === fieldKey);
        
        if (field) {
          // Validate just this field for this row
          const value = row[fieldKey as keyof typeof row];
          const errors = validateField(value, field as Field<T>);
          
          if (errors.length > 0) {
            // Store the validation error
            validationErrors.set(rowIndex, {
              [fieldKey]: {
                message: errors[0].message,
                level: errors[0].level as 'info' | 'warning' | 'error',
                source: ErrorSources.Row,
                type: errors[0].type
              }
            });
          }
          
          // Check if the field requires uniqueness validation or if it's item_number after UPC/Supplier change
          const needsUniquenessCheck = isUniqueField || 
                                     field.validations?.some(v => v.rule === 'unique');
          
          if (needsUniquenessCheck) {
            console.log(`Running immediate uniqueness validation for field ${fieldKey}`);
            
            // For item_number updated via UPC validation, or direct UPC update, check both fields
            if (fieldKey === 'item_number' || fieldKey === 'upc' || fieldKey === 'barcode') {
              // Validate both item_number and UPC/barcode fields for uniqueness
              const itemNumberUniqueErrors = validateUniqueField(data, 'item_number');
              const upcUniqueErrors = validateUniqueField(data, fieldKey === 'item_number' ? 'upc' : fieldKey);
              
              // Combine the errors
              itemNumberUniqueErrors.forEach((errors, rowIdx) => {
                if (!validationErrors.has(rowIdx)) {
                  validationErrors.set(rowIdx, {});
                }
                Object.assign(validationErrors.get(rowIdx)!, errors);
              });
              
              upcUniqueErrors.forEach((errors, rowIdx) => {
                if (!validationErrors.has(rowIdx)) {
                  validationErrors.set(rowIdx, {});
                }
                Object.assign(validationErrors.get(rowIdx)!, errors);
              });
            } else {
              // Normal uniqueness validation for other fields
              const uniqueErrors = validateUniqueField(data, fieldKey);
              
              // Add unique errors to validation errors
              uniqueErrors.forEach((errors, rowIdx) => {
                if (!validationErrors.has(rowIdx)) {
                  validationErrors.set(rowIdx, {});
                }
                Object.assign(validationErrors.get(rowIdx)!, errors);
              });
            }
          }
        }
      }
    } else {
      // Full validation - all fields for all rows
      console.log('Running full validation for all fields and rows');
      
      // Process each row for field-level validations
      for (let rowIndex = 0; rowIndex < data.length; rowIndex++) {
        const row = data[rowIndex];
        let rowErrors: Record<string, InfoWithSource> = {};
        
        // Validate all fields for this row
        fields.forEach(field => {
          const fieldKey = String(field.key);
          const value = row[fieldKey as keyof typeof row];
          const errors = validateField(value, field as Field<T>);
          
          if (errors.length > 0) {
            rowErrors[fieldKey] = {
              message: errors[0].message,
              level: errors[0].level as 'info' | 'warning' | 'error',
              source: ErrorSources.Row,
              type: errors[0].type
            };
          }
        });
        
        // Add row to validationErrors if it has any errors
        if (Object.keys(rowErrors).length > 0) {
          validationErrors.set(rowIndex, rowErrors);
        }
      }
      
      // Validate all unique fields
      const uniqueErrors = validateAllUniqueFields(data);
      
      // Merge in unique errors
      uniqueErrors.forEach((errors, rowIdx) => {
        if (!validationErrors.has(rowIdx)) {
          validationErrors.set(rowIdx, {});
        }
        Object.assign(validationErrors.get(rowIdx)!, errors);
      });
      
      console.log('Uniqueness validation complete');
    }
    
    return {
      data,
      validationErrors
    };
  }, [fields, validateField, validateUniqueField, validateAllUniqueFields]);

  return {
    validateData,
    validateField,
    validateRow,
    validateUniqueField,
    clearValidationCacheForField,
    clearAllUniquenessCaches
  };
} 