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

export const useUniqueItemNumbersValidation = <T extends string>(
  data: RowData<T>[],
  fields: Fields<T>,
  setValidationErrors: React.Dispatch<React.SetStateAction<Map<number, Record<string, ValidationError[]>>>>
) => {
  // Update validateUniqueItemNumbers to also check for uniqueness of UPC/barcode
  const validateUniqueItemNumbers = useCallback(async () => {
    console.log("Validating unique fields");

    // Skip if no data
    if (!data.length) return;

    // Track unique identifiers in maps
    const uniqueFieldsMap = new Map<string, Map<string, number[]>>();

    // Find fields that need uniqueness validation
    const uniqueFields = fields
      .filter((field) => field.validations?.some((v) => v.rule === "unique"))
      .map((field) => String(field.key));

    console.log(
      `Found ${uniqueFields.length} fields requiring uniqueness validation:`,
      uniqueFields
    );

    // Always check item_number uniqueness even if not explicitly defined
    if (!uniqueFields.includes("item_number")) {
      uniqueFields.push("item_number");
    }

    // Initialize maps for each unique field
    uniqueFields.forEach((fieldKey) => {
      uniqueFieldsMap.set(fieldKey, new Map<string, number[]>());
    });

    // Initialize batch updates
    const errors = new Map<number, Record<string, ValidationError[]>>();

    // Single pass through data to identify all unique values
    data.forEach((row, index) => {
      uniqueFields.forEach((fieldKey) => {
        const value = row[fieldKey as keyof typeof row];

        // Skip empty values
        if (value === undefined || value === null || value === "") {
          return;
        }

        const valueStr = String(value);
        const fieldMap = uniqueFieldsMap.get(fieldKey);

        if (fieldMap) {
          // Get or initialize the array of indices for this value
          const indices = fieldMap.get(valueStr) || [];
          indices.push(index);
          fieldMap.set(valueStr, indices);
        }
      });
    });

    // Process duplicates
    uniqueFields.forEach((fieldKey) => {
      const fieldMap = uniqueFieldsMap.get(fieldKey);
      if (!fieldMap) return;

      fieldMap.forEach((indices, value) => {
        // Only process if there are duplicates
        if (indices.length > 1) {
          // Get the validation rule for this field
          const field = fields.find((f) => String(f.key) === fieldKey);
          const validationRule = field?.validations?.find(
            (v) => v.rule === "unique"
          );

          const errorObj = {
            message:
              validationRule?.errorMessage || `Duplicate ${fieldKey}: ${value}`,
            level: validationRule?.level || ("error" as "error"),
            source: ErrorSources.Table,
            type: ErrorType.Unique,
          };

          // Add error to each row with this value
          indices.forEach((rowIndex) => {
            const rowErrors = errors.get(rowIndex) || {};
            rowErrors[fieldKey] = [errorObj];
            errors.set(rowIndex, rowErrors);
          });
        }
      });
    });

    // Apply batch updates only if we have errors to report
    if (errors.size > 0) {
      // OPTIMIZATION: Check if we actually have new errors before updating state
      let hasChanges = false;

      // We'll update errors with a single batch operation
      setValidationErrors((prev) => {
        const newMap = new Map(prev);

        // Check each row for changes
        errors.forEach((rowErrors, rowIndex) => {
          const existingErrors = newMap.get(rowIndex) || {};
          const updatedErrors = { ...existingErrors };
          let rowHasChanges = false;

          // Check each field for changes
          Object.entries(rowErrors).forEach(([fieldKey, fieldErrors]) => {
            // Compare with existing errors
            const existingFieldErrors = existingErrors[fieldKey];

            if (
              !existingFieldErrors ||
              existingFieldErrors.length !== fieldErrors.length ||
              !existingFieldErrors.every(
                (err, idx) =>
                  err.message === fieldErrors[idx].message &&
                  err.type === fieldErrors[idx].type
              )
            ) {
              // We have a change
              updatedErrors[fieldKey] = fieldErrors;
              rowHasChanges = true;
              hasChanges = true;
            }
          });

          // Only update if we have changes
          if (rowHasChanges) {
            newMap.set(rowIndex, updatedErrors);
          }
        });

        // Only return a new map if we have changes
        return hasChanges ? newMap : prev;
      });
    }

    console.log("Uniqueness validation complete");
  }, [data, fields, setValidationErrors]);

  return {
    validateUniqueItemNumbers
  };
}; 