import { useCallback } from 'react';
import type { Fields } from '../../../types';
import { ErrorSources, ErrorType } from '../../../types';
import { RowData, InfoWithSource, isEmpty } from './validationTypes';

export const useUniqueValidation = <T extends string>(
  fields: Fields<T>
) => {
  // Additional function to explicitly validate uniqueness for specified fields
  const validateUniqueField = useCallback((data: RowData<T>[], fieldKey: string) => {
    // Field keys that need special handling for uniqueness
    const uniquenessFields = ['item_number', 'upc', 'barcode', 'supplier_no', 'notions_no'];
    
    // If the field doesn't need uniqueness validation, return empty errors
    if (!uniquenessFields.includes(fieldKey)) {
      const field = fields.find(f => String(f.key) === fieldKey);
      if (!field || !field.validations?.some(v => v.rule === 'unique')) {
        return new Map<number, Record<string, InfoWithSource>>();
      }
    }
    
    // Create map to track errors
    const uniqueErrors = new Map<number, Record<string, InfoWithSource>>();
    
    // Find the field definition
    const field = fields.find(f => String(f.key) === fieldKey);
    if (!field) return uniqueErrors;
    
    // Get validation properties
    const validation = field.validations?.find(v => v.rule === 'unique');
    const allowEmpty = validation?.allowEmpty ?? false;
    const errorMessage = validation?.errorMessage || `${field.label} must be unique`;
    const level = validation?.level || 'error';
    
    // Track values for uniqueness check
    const valueMap = new Map<string, number[]>();
    
    // Build value map
    data.forEach((row, rowIndex) => {
      const value = String(row[fieldKey as keyof typeof row] || '');
      
      // Skip empty values if allowed
      if (allowEmpty && isEmpty(value)) {
        return;
      }
      
      if (!valueMap.has(value)) {
        valueMap.set(value, [rowIndex]);
      } else {
        valueMap.get(value)?.push(rowIndex);
      }
    });
    
    // Add errors for duplicate values
    valueMap.forEach((rowIndexes, value) => {
      if (rowIndexes.length > 1) {
        // Skip empty values
        if (!value || value.trim() === '') return;
        
        // Add error to all duplicate rows
        rowIndexes.forEach(rowIndex => {
          // Create errors object if needed
          if (!uniqueErrors.has(rowIndex)) {
            uniqueErrors.set(rowIndex, {});
          }
          
          // Add error for this field
          uniqueErrors.get(rowIndex)![fieldKey] = {
            message: errorMessage,
            level: level as 'info' | 'warning' | 'error',
            source: ErrorSources.Table,
            type: ErrorType.Unique
          };
        });
      }
    });
    
    return uniqueErrors;
  }, [fields]);

  // Validate uniqueness for multiple fields
  const validateUniqueFields = useCallback((data: RowData<T>[], fieldKeys: string[]) => {
    // Process each field and merge results
    const allErrors = new Map<number, Record<string, InfoWithSource>>();
    
    fieldKeys.forEach(fieldKey => {
      const fieldErrors = validateUniqueField(data, fieldKey);
      
      // Merge errors
      fieldErrors.forEach((errors, rowIdx) => {
        if (!allErrors.has(rowIdx)) {
          allErrors.set(rowIdx, {});
        }
        Object.assign(allErrors.get(rowIdx)!, errors);
      });
    });
    
    return allErrors;
  }, [validateUniqueField]);

  // Run complete validation for uniqueness
  const validateAllUniqueFields = useCallback((data: RowData<T>[]) => {
    // Get fields requiring uniqueness validation
    const uniqueFields = fields
      .filter(field => field.validations?.some(v => v.rule === 'unique'))
      .map(field => String(field.key));
    
    // Also add standard unique fields that might not be explicitly marked as unique
    const standardUniqueFields = ['item_number', 'upc', 'barcode', 'supplier_no', 'notions_no'];
    
    // Combine all fields that need uniqueness validation
    const allUniqueFieldKeys = [...new Set([
      ...uniqueFields,
      ...standardUniqueFields
    ])];
    
    // Filter to only fields that exist in the data
    const existingFields = allUniqueFieldKeys.filter(fieldKey => 
      data.some(row => fieldKey in row)
    );
    
    // Validate all fields at once
    return validateUniqueFields(data, existingFields);
  }, [fields, validateUniqueFields]);

  return {
    validateUniqueField,
    validateUniqueFields,
    validateAllUniqueFields
  };
}; 