import { useState, useEffect, useRef } from 'react';
import type { Dispatch, SetStateAction } from 'react';
import type { Fields } from '@/components/product-import/types';
import type { RowData } from './validationTypes';
import { cleanPriceField } from '../utils/priceUtils';

/**
 * Custom hook for handling initial data validation
 *
 * Performs comprehensive validation on import data including:
 * - Price field cleaning and formatting
 * - Required field validation
 * - Regex pattern validation
 * - Batch processing for performance
 *
 * @param data - Array of row data to validate
 * @param fields - Field configuration with validation rules
 * @param setData - Function to update data after cleaning
 * @param setValidationErrors - Function to set validation errors
 * @param validateUniqueItemNumbers - Async function to validate uniqueness
 * @param upcValidationComplete - Flag indicating UPC validation is done
 * @param onComplete - Callback when validation is complete
 */
export function useInitialValidation<T extends string>({
  data,
  fields,
  setData,
  setValidationErrors,
  validateUniqueItemNumbers,
  upcValidationComplete,
  onComplete,
}: {
  data: RowData<T>[];
  fields: Fields<T>;
  setData: (data: RowData<T>[]) => void;
  setValidationErrors: Dispatch<SetStateAction<Map<number, Record<string, any[]>>>>;
  validateUniqueItemNumbers: () => Promise<void>;
  upcValidationComplete: boolean;
  onComplete?: () => void;
}) {
  const hasRunRef = useRef(false);
  const [isValidating, setIsValidating] = useState(false);

  useEffect(() => {
    // Only run once
    if (hasRunRef.current) return;

    // Wait for UPC validation to complete first
    if (!upcValidationComplete) return;

    // Handle empty dataset immediately
    if (!data || data.length === 0) {
      hasRunRef.current = true;
      if (onComplete) {
        onComplete();
      }
      return;
    }

    hasRunRef.current = true;
    setIsValidating(true);

    const runValidation = async () => {
      console.log('Running initial validation...');

      // Extract field groups for validation
      const requiredFields = fields.filter((field) =>
        field.validations?.some((v) => v.rule === 'required')
      );
      const regexFields = fields.filter((field) =>
        field.validations?.some((v) => v.rule === 'regex')
      );

      console.log(`Validating ${requiredFields.length} required fields, ${regexFields.length} regex fields`);

      // Dynamic batch size based on dataset size
      const BATCH_SIZE = data.length <= 50 ? data.length : 25;
      const totalBatches = Math.ceil(data.length / BATCH_SIZE);

      // Initialize containers
      const newData = [...data];
      const validationErrorsTemp = new Map<number, Record<string, any[]>>();

      // Process batches
      for (let batchNum = 0; batchNum < totalBatches; batchNum++) {
        const startIdx = batchNum * BATCH_SIZE;
        const endIdx = Math.min(startIdx + BATCH_SIZE, data.length);

        console.log(`Processing batch ${batchNum + 1}/${totalBatches} (rows ${startIdx}-${endIdx - 1})`);

        // Process all rows in this batch
        const batchPromises = [];

        for (let rowIndex = startIdx; rowIndex < endIdx; rowIndex++) {
          batchPromises.push(
            processRow(
              rowIndex,
              data[rowIndex],
              newData,
              requiredFields,
              regexFields,
              validationErrorsTemp
            )
          );
        }

        await Promise.all(batchPromises);

        // Yield to UI thread for large datasets
        if (batchNum % 2 === 1 || data.length > 500) {
          await new Promise((resolve) => setTimeout(resolve, data.length > 1000 ? 10 : 5));
        }
      }

      console.log('Batch validation complete, applying results...');

      // Apply validation errors
      setValidationErrors(validationErrorsTemp);

      // Apply data changes (price formatting)
      if (JSON.stringify(data) !== JSON.stringify(newData)) {
        setData(newData);
      }

      // Run uniqueness validation
      console.log('Running uniqueness validation...');
      await validateUniqueItemNumbers();

      console.log('Initial validation complete');
      setIsValidating(false);

      // Notify completion
      if (onComplete) {
        onComplete();
      }
    };

    runValidation().catch((error) => {
      console.error('Error during initial validation:', error);
      setIsValidating(false);
      if (onComplete) {
        onComplete();
      }
    });
  }, [data, fields, setData, setValidationErrors, validateUniqueItemNumbers, upcValidationComplete, onComplete]);

  return { isValidating };
}

/**
 * Process a single row: clean data and validate
 */
function processRow<T extends string>(
  rowIndex: number,
  row: RowData<T>,
  newData: RowData<T>[],
  requiredFields: Fields<T>,
  regexFields: Fields<T>,
  validationErrorsTemp: Map<number, Record<string, any[]>>
): Promise<void> {
  return new Promise((resolve) => {
    // Skip empty rows
    if (!row) {
      resolve();
      return;
    }

    const fieldErrors: Record<string, any[]> = {};
    let hasErrors = false;
    const rowAsRecord = row as Record<string, any>;

    // Clean price fields if needed
    let needsUpdate = false;
    let cleanedRow = row;

    if (
      rowAsRecord.msrp &&
      typeof rowAsRecord.msrp === 'string' &&
      (rowAsRecord.msrp.includes('$') || rowAsRecord.msrp.includes(','))
    ) {
      if (!needsUpdate) {
        cleanedRow = { ...row } as RowData<T>;
        needsUpdate = true;
      }
      (cleanedRow as Record<string, any>).msrp = cleanPriceField(rowAsRecord.msrp);
    }

    if (
      rowAsRecord.cost_each &&
      typeof rowAsRecord.cost_each === 'string' &&
      (rowAsRecord.cost_each.includes('$') || rowAsRecord.cost_each.includes(','))
    ) {
      if (!needsUpdate) {
        cleanedRow = { ...row } as RowData<T>;
        needsUpdate = true;
      }
      (cleanedRow as Record<string, any>).cost_each = cleanPriceField(rowAsRecord.cost_each);
    }

    if (needsUpdate) {
      newData[rowIndex] = cleanedRow;
    }

    // Validate required fields
    for (const field of requiredFields) {
      const key = String(field.key);
      const value = row[key as keyof typeof row];

      if (
        value === undefined ||
        value === null ||
        value === '' ||
        (Array.isArray(value) && value.length === 0) ||
        (typeof value === 'object' && value !== null && Object.keys(value).length === 0)
      ) {
        fieldErrors[key] = [
          {
            message:
              field.validations?.find((v) => v.rule === 'required')?.errorMessage ||
              'This field is required',
            level: 'error',
            source: 'row',
            type: 'required',
          },
        ];
        hasErrors = true;
      }
    }

    // Validate regex fields
    for (const field of regexFields) {
      const key = String(field.key);
      const value = row[key as keyof typeof row];

      // Skip empty values (handled by required validation)
      if (value === undefined || value === null || value === '') {
        continue;
      }

      const regexValidation = field.validations?.find((v) => v.rule === 'regex');
      if (regexValidation) {
        try {
          const regex = new RegExp(regexValidation.value, regexValidation.flags);
          if (!regex.test(String(value))) {
            fieldErrors[key] = [
              {
                message: regexValidation.errorMessage,
                level: regexValidation.level || 'error',
                source: 'row',
                type: 'regex',
              },
            ];
            hasErrors = true;
          }
        } catch (error) {
          console.error('Invalid regex in validation:', error);
        }
      }
    }

    // Store errors if any
    if (hasErrors) {
      validationErrorsTemp.set(rowIndex, fieldErrors);
    }

    resolve();
  });
}
